Static Value-Flow Analysis
Loading...
Searching...
No Matches
ExtAPI.cpp
Go to the documentation of this file.
1//===- ExtAPI.cpp -- External functions -----------------------------------------//
2//
3// SVF: Static Value-Flow Analysis
4//
5// Copyright (C) <2013-2017> <Yulei Sui>
6//
7
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU Affero General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Affero General Public License for more details.
17
18// You should have received a copy of the GNU Affero General Public License
19// along with this program. If not, see <http://www.gnu.org/licenses/>.
20//
21//===----------------------------------------------------------------------===//
22
23/*
24 * ExtAPI.cpp
25 *
26 * Created on: July 1, 2022
27 * Author: Shuangxiang Kan
28 */
29
30#include "Util/ExtAPI.h"
31#include "Util/SVFUtil.h"
32#include "Util/Options.h"
33#include "Util/config.h"
34#include <ostream>
35#include <sys/stat.h>
36#include "SVFIR/SVFVariables.h"
37#include <dlfcn.h>
38
39using namespace SVF;
40
41ExtAPI* ExtAPI::extOp = nullptr;
42std::string ExtAPI::extBcPath = "";
43
45{
46 if (extOp == nullptr)
47 {
48 extOp = new ExtAPI;
49 }
50 return extOp;
51}
52
54{
55 if (extOp != nullptr)
56 {
57 delete extOp;
58 extOp = nullptr;
59 }
60}
61
62// Set extapi.bc file path
63bool ExtAPI::setExtBcPath(const std::string& path)
64{
65 struct stat statbuf;
66 if (!path.empty() && !stat(path.c_str(), &statbuf))
67 {
69 return true;
70 }
71 return false;
72}
73
74// Get stdout from a shell command.
75// Return empty string if the command fails.
76static std::string GetStdoutFromCommand(const std::string& command)
77{
78 char buffer[128];
79 std::string result;
80
81 FILE* pipe = popen(command.c_str(), "r");
82 if (!pipe)
83 return "";
84
85 while (fgets(buffer, sizeof(buffer), pipe) != nullptr)
86 {
87 result += buffer;
88 }
89
90 int status = pclose(pipe);
91 if (status != 0)
92 return "";
93
94 // remove trailing newlines
95 result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
96 result.erase(std::remove(result.begin(), result.end(), '\r'), result.end());
97
98 return result;
99}
100
101// Get extapi.bc file path from SVF_DIR or npm installation
102static std::string getFilePath(const std::string& path)
103{
104 std::string bcFilePath;
105
106 if (path == "SVF_DIR")
107 {
108 const char* svfdir = getenv("SVF_DIR");
109 if (!svfdir)
110 return "";
111
113
114 if (!bcFilePath.empty() && bcFilePath.back() != '/')
115 bcFilePath.push_back('/');
116
117 bcFilePath.append(SVF_BUILD_TYPE "-build/lib/extapi.bc");
118 }
119 else if (path == "npm root")
120 {
121 // Check npm exists before calling `npm root`.
122 // If npm is missing, this command returns empty.
124 "command -v npm >/dev/null 2>&1 && npm root"
125 );
126
127 if (bcFilePath.empty())
128 return "";
129
130 if (bcFilePath.back() != '/')
131 bcFilePath.push_back('/');
132
133 bcFilePath.append("SVF/lib/extapi.bc");
134 }
135
136 return bcFilePath;
137}
138
139// This function returns the absolute path of the current module:
140// - If SVF is built and loaded as a dynamic library (e.g., libSVFCore.so or .dylib), it returns the path to that shared object file.
141// - If SVF is linked as a static library, it returns the path to the main executable.
142// This is useful for locating resource files (such as extapi.bc) relative to the module at runtime.
143std::string getCurrentSOPath()
144{
146 if (dladdr((void*)&getCurrentSOPath, &info) && info.dli_fname)
147 {
148 return std::string(info.dli_fname);
149 }
150 return "";
151}
152
153// Get extapi.bc path
155{
156 // Try to locate extapi.bc in the following order:
157 // 1. If setExtBcPath() has been called, use that path.
158 // 2. If the command line argument -extapi=path/to/extapi.bc is provided, use that path.
159 // 3. If SVF is being developed and used directly from a build directory, try the build dir (SVF_BUILD_DIR).
160 // 4. If the SVF_DIR environment variable is set, try $SVF_DIR with the standard relative path.
161 // 5. If installed via npm, use `npm root` and append the standard relative path.
162 // 6. As a last resort, use the directory of the loaded libSVFCore.so (or .dylib) and append extapi.bc.
163
164 std::vector<std::string> candidatePaths;
165
166 // 1. Use path set by setExtBcPath()
167 if (!extBcPath.empty())
168 return extBcPath;
169
170 // 2. Use command line argument -extapi=...
172 {
173 return extBcPath;
174 }
175 else
176 {
178 }
179
180 // 3. SVF developer: try build directory (SVF_BUILD_DIR)
181 if (setExtBcPath(SVF_BUILD_DIR "/lib/extapi.bc"))
182 {
183 return extBcPath;
184 }
185 else
186 {
187 candidatePaths.push_back(SVF_BUILD_DIR "/lib/extapi.bc");
188 }
189
190 // 4. Use $SVF_DIR environment variable + standard relative path
191 if (setExtBcPath(getFilePath("SVF_DIR")))
192 {
193 return extBcPath;
194 }
195 else
196 {
197 candidatePaths.push_back(getFilePath("SVF_DIR"));
198 }
199
200 // 5. Use npm root + standard relative path (for npm installations)
201 std::string npmPath = getFilePath("npm root");
203 {
204 return extBcPath;
205 }
206 else
207 {
208 candidatePaths.push_back(npmPath.empty() ? "npm root unavailable" : npmPath);
209 }
210
211 // 6. Use the directory of the loaded libSVFCore.so/.dylib + extapi.bc
212 std::string soPath = getCurrentSOPath();
213 if (!soPath.empty())
214 {
215 std::string dir = soPath.substr(0, soPath.find_last_of('/'));
216 std::string candidate = dir + "/extapi.bc";
218 {
219 return extBcPath;
220 }
221 else
222 {
223 candidatePaths.push_back(candidate);
224 }
225 }
226
227 // If all candidate paths failed, print error and suggestions
228 SVFUtil::errs() << "ERROR: Failed to locate \"extapi.bc\". Tried the following candidate paths:" << std::endl;
229 for (const auto& path : candidatePaths)
230 {
231 SVFUtil::errs() << " " << path << std::endl;
232 }
233 SVFUtil::errs() << "To override the default locations for \"extapi.bc\", you can:" << std::endl
234 << "\t1. Use the command line argument \"-extapi=path/to/extapi.bc\"" << std::endl
235 << "\t2. Use the \"setExtBcPath()\" function *BEFORE* calling \"buildSVFModule()\"" << std::endl
236 << "\t3. Override the paths in \"include/SVF/Util/config.h\" (WARNING: will be overwritten "
237 << "when rebuilding SVF (generated by CMakeLists.txt))" << std::endl;
238 abort();
239}
240
241
242void ExtAPI::setExtFuncAnnotations(const FunObjVar* fun, const std::vector<std::string>& funcAnnotations)
243{
244 assert(fun && "Null FunObjVar* pointer");
246}
247
248bool ExtAPI::hasExtFuncAnnotation(const FunObjVar *fun, const std::string &funcAnnotation)
249{
250 assert(fun && "Null FunObjVar* pointer");
251 auto it = funObjVar2Annotations.find(fun);
252 if (it != funObjVar2Annotations.end())
253 {
254 for (const std::string& annotation : it->second)
255 if (annotation.find(funcAnnotation) != std::string::npos)
256 return true;
257 }
258 return false;
259}
260
261
262std::string ExtAPI::getExtFuncAnnotation(const FunObjVar* fun, const std::string& funcAnnotation)
263{
264 assert(fun && "Null FunObjVar* pointer");
265 auto it = funObjVar2Annotations.find(fun);
266 if (it != funObjVar2Annotations.end())
267 {
268 for (const std::string& annotation : it->second)
269 if (annotation.find(funcAnnotation) != std::string::npos)
270 return annotation;
271 }
272 return "";
273}
274
275const std::vector<std::string>& ExtAPI::getExtFuncAnnotations(const FunObjVar* fun)
276{
277 assert(fun && "Null FunObjVar* pointer");
278 auto it = funObjVar2Annotations.find(fun);
279 if (it != funObjVar2Annotations.end())
280 return it->second;
281 return funObjVar2Annotations[fun];
282}
283
285{
286 return F &&
287 (hasExtFuncAnnotation(F, "MEMCPY") || hasExtFuncAnnotation(F, "STRCPY")
288 || hasExtFuncAnnotation(F, "STRCAT"));
289}
290
292{
293 return F && hasExtFuncAnnotation(F, "MEMSET");
294}
295
297{
298 return F && hasExtFuncAnnotation(F, "ALLOC_HEAP_RET");
299}
300
301// Does (F) allocate a new object and assign it to one of its arguments?
303{
304 return F && hasExtFuncAnnotation(F, "ALLOC_HEAP_ARG");
305}
306
308{
309 return F && hasExtFuncAnnotation(F, "ALLOC_STACK_RET");
310}
311
312// Get the position of argument which holds the new object
314{
315 std::string allocArg = getExtFuncAnnotation(F, "ALLOC_HEAP_ARG");
316 assert(!allocArg.empty() && "Not an alloc call via argument or incorrect extern function annotation!");
317
318 std::string number;
319 for (char c : allocArg)
320 {
321 if (isdigit(c))
322 number.push_back(c);
323 }
324 assert(!number.empty() && "Incorrect naming convention for svf external functions(ALLOC_HEAP_ARG + number)?");
325 return std::stoi(number);
326}
327
328// Does (F) reallocate a new object?
330{
331 return F && hasExtFuncAnnotation(F, "REALLOC_HEAP_RET");
332}
334{
335 assert(F && "Null FunObjVar* pointer");
336 if (F->isDeclaration() || F->isIntrinsic())
337 return true;
338 else if (hasExtFuncAnnotation(F, "OVERWRITE") && getExtFuncAnnotations(F).size() == 1)
339 return false;
340 else
341 return !getExtFuncAnnotations(F).empty();
342}
static std::string GetStdoutFromCommand(const std::string &command)
Definition ExtAPI.cpp:76
static std::string getFilePath(const std::string &path)
Definition ExtAPI.cpp:102
std::string getCurrentSOPath()
Definition ExtAPI.cpp:143
char * buffer
Definition cJSON.h:163
const char *const const double number
Definition cJSON.h:268
bool is_alloc_stack_ret(const FunObjVar *F)
Definition ExtAPI.cpp:307
bool is_arg_alloc(const FunObjVar *F)
Definition ExtAPI.cpp:302
bool is_memcpy(const FunObjVar *F)
Definition ExtAPI.cpp:284
std::string getExtBcPath()
Definition ExtAPI.cpp:154
static std::string extBcPath
Definition ExtAPI.h:59
static ExtAPI * extOp
Definition ExtAPI.h:53
s32_t get_alloc_arg_pos(const FunObjVar *F)
Definition ExtAPI.cpp:313
static ExtAPI * getExtAPI()
Definition ExtAPI.cpp:44
bool is_ext(const FunObjVar *funObjVar)
Definition ExtAPI.cpp:333
std::string getExtFuncAnnotation(const FunObjVar *fun, const std::string &funcAnnotation)
Definition ExtAPI.cpp:262
bool is_realloc(const FunObjVar *F)
Definition ExtAPI.cpp:329
Map< const FunObjVar *, std::vector< std::string > > funObjVar2Annotations
Definition ExtAPI.h:56
void setExtFuncAnnotations(const FunObjVar *fun, const std::vector< std::string > &funcAnnotations)
Definition ExtAPI.cpp:242
ExtAPI()=default
static void destory()
Definition ExtAPI.cpp:53
static bool setExtBcPath(const std::string &path)
Definition ExtAPI.cpp:63
bool hasExtFuncAnnotation(const FunObjVar *fun, const std::string &funcAnnotation)
Definition ExtAPI.cpp:248
bool is_alloc(const FunObjVar *F)
Definition ExtAPI.cpp:296
const std::vector< std::string > & getExtFuncAnnotations(const FunObjVar *fun)
Definition ExtAPI.cpp:275
bool is_memset(const FunObjVar *F)
Definition ExtAPI.cpp:291
bool isIntrinsic() const
bool isDeclaration() const
static const Option< std::string > ExtAPIPath
Definition Options.h:213
char * fgets(char *str, int n, void *stream)
Definition extapi.c:869
int isdigit(int c)
Definition extapi.c:974
char * getenv(const char *name)
Definition extapi.c:1172
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
for isBitcode
Definition BasicTypes.h:70
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
signed s32_t
Definition GeneralType.h:68