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 environment variables $SVF_DIR and "npm root" through popen() method
75static std::string GetStdoutFromCommand(const std::string& command)
76{
77 char buffer[128];
78 std::string result = "";
79 // Open pipe to file
80 FILE* pipe = popen(command.c_str(), "r");
81 if (!pipe)
82 {
83 return "popen failed!";
84 }
85 // read till end of process:
86 while (!feof(pipe))
87 {
88 // use buffer to read and add to result
89 if (fgets(buffer, 128, pipe) != NULL)
90 result += buffer;
91 }
92 pclose(pipe);
93 // remove "\n"
94 result.erase(remove(result.begin(), result.end(), '\n'), result.end());
95 return result;
96}
97
98// Get extapi.bc file path in npm
99static std::string getFilePath(const std::string& path)
100{
101 std::string bcFilePath = "";
102 if (path.compare("SVF_DIR") == 0)
103 {
104 char const* svfdir = getenv("SVF_DIR");
105 if (svfdir)
107 if (!bcFilePath.empty() && bcFilePath.back() != '/')
108 bcFilePath.push_back('/');
109 bcFilePath.append(SVF_BUILD_TYPE "-build").append("/lib/extapi.bc");
110 }
111 else if (path.compare("npm root") == 0)
112 {
114 if (!bcFilePath.empty() && bcFilePath.back() != '/')
115 bcFilePath.push_back('/');
116 bcFilePath.append("SVF/lib/extapi.bc");
117 }
118 return bcFilePath;
119}
120
121// This function returns the absolute path of the current module:
122// - 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.
123// - If SVF is linked as a static library, it returns the path to the main executable.
124// This is useful for locating resource files (such as extapi.bc) relative to the module at runtime.
125std::string getCurrentSOPath()
126{
128 if (dladdr((void*)&getCurrentSOPath, &info) && info.dli_fname)
129 {
130 return std::string(info.dli_fname);
131 }
132 return "";
133}
134
135// Get extapi.bc path
137{
138 // Try to locate extapi.bc in the following order:
139 // 1. If setExtBcPath() has been called, use that path.
140 // 2. If the command line argument -extapi=path/to/extapi.bc is provided, use that path.
141 // 3. If SVF is being developed and used directly from a build directory, try the build dir (SVF_BUILD_DIR).
142 // 4. If the SVF_DIR environment variable is set, try $SVF_DIR with the standard relative path.
143 // 5. If installed via npm, use `npm root` and append the standard relative path.
144 // 6. As a last resort, use the directory of the loaded libSVFCore.so (or .dylib) and append extapi.bc.
145
146 std::vector<std::string> candidatePaths;
147
148 // 1. Use path set by setExtBcPath()
149 if (!extBcPath.empty())
150 return extBcPath;
151
152 // 2. Use command line argument -extapi=...
154 {
155 return extBcPath;
156 }
157 else
158 {
160 }
161
162 // 3. SVF developer: try build directory (SVF_BUILD_DIR)
163 if (setExtBcPath(SVF_BUILD_DIR "/lib/extapi.bc"))
164 {
165 return extBcPath;
166 }
167 else
168 {
169 candidatePaths.push_back(SVF_BUILD_DIR "/lib/extapi.bc");
170 }
171
172 // 4. Use $SVF_DIR environment variable + standard relative path
173 if (setExtBcPath(getFilePath("SVF_DIR")))
174 {
175 return extBcPath;
176 }
177 else
178 {
179 candidatePaths.push_back(getFilePath("SVF_DIR"));
180 }
181
182 // 5. Use npm root + standard relative path (for npm installations)
183 if (setExtBcPath(getFilePath("npm root")))
184 {
185 return extBcPath;
186 }
187 else
188 {
189 candidatePaths.push_back(getFilePath("npm root"));
190 }
191
192 // 6. Use the directory of the loaded libSVFCore.so/.dylib + extapi.bc
193 std::string soPath = getCurrentSOPath();
194 if (!soPath.empty())
195 {
196 std::string dir = soPath.substr(0, soPath.find_last_of('/'));
197 std::string candidate = dir + "/extapi.bc";
199 {
200 return extBcPath;
201 }
202 else
203 {
204 candidatePaths.push_back(candidate);
205 }
206 }
207
208 // If all candidate paths failed, print error and suggestions
209 SVFUtil::errs() << "ERROR: Failed to locate \"extapi.bc\". Tried the following candidate paths:" << std::endl;
210 for (const auto& path : candidatePaths)
211 {
212 SVFUtil::errs() << " " << path << std::endl;
213 }
214 SVFUtil::errs() << "To override the default locations for \"extapi.bc\", you can:" << std::endl
215 << "\t1. Use the command line argument \"-extapi=path/to/extapi.bc\"" << std::endl
216 << "\t2. Use the \"setExtBcPath()\" function *BEFORE* calling \"buildSVFModule()\"" << std::endl
217 << "\t3. Override the paths in \"include/SVF/Util/config.h\" (WARNING: will be overwritten "
218 << "when rebuilding SVF (generated by CMakeLists.txt))" << std::endl;
219 abort();
220}
221
222
223void ExtAPI::setExtFuncAnnotations(const FunObjVar* fun, const std::vector<std::string>& funcAnnotations)
224{
225 assert(fun && "Null FunObjVar* pointer");
227}
228
229bool ExtAPI::hasExtFuncAnnotation(const FunObjVar *fun, const std::string &funcAnnotation)
230{
231 assert(fun && "Null FunObjVar* pointer");
232 auto it = funObjVar2Annotations.find(fun);
233 if (it != funObjVar2Annotations.end())
234 {
235 for (const std::string& annotation : it->second)
236 if (annotation.find(funcAnnotation) != std::string::npos)
237 return true;
238 }
239 return false;
240}
241
242
243std::string ExtAPI::getExtFuncAnnotation(const FunObjVar* fun, const std::string& funcAnnotation)
244{
245 assert(fun && "Null FunObjVar* pointer");
246 auto it = funObjVar2Annotations.find(fun);
247 if (it != funObjVar2Annotations.end())
248 {
249 for (const std::string& annotation : it->second)
250 if (annotation.find(funcAnnotation) != std::string::npos)
251 return annotation;
252 }
253 return "";
254}
255
256const std::vector<std::string>& ExtAPI::getExtFuncAnnotations(const FunObjVar* fun)
257{
258 assert(fun && "Null FunObjVar* pointer");
259 auto it = funObjVar2Annotations.find(fun);
260 if (it != funObjVar2Annotations.end())
261 return it->second;
262 return funObjVar2Annotations[fun];
263}
264
266{
267 return F &&
268 (hasExtFuncAnnotation(F, "MEMCPY") || hasExtFuncAnnotation(F, "STRCPY")
269 || hasExtFuncAnnotation(F, "STRCAT"));
270}
271
273{
274 return F && hasExtFuncAnnotation(F, "MEMSET");
275}
276
278{
279 return F && hasExtFuncAnnotation(F, "ALLOC_HEAP_RET");
280}
281
282// Does (F) allocate a new object and assign it to one of its arguments?
284{
285 return F && hasExtFuncAnnotation(F, "ALLOC_HEAP_ARG");
286}
287
289{
290 return F && hasExtFuncAnnotation(F, "ALLOC_STACK_RET");
291}
292
293// Get the position of argument which holds the new object
295{
296 std::string allocArg = getExtFuncAnnotation(F, "ALLOC_HEAP_ARG");
297 assert(!allocArg.empty() && "Not an alloc call via argument or incorrect extern function annotation!");
298
299 std::string number;
300 for (char c : allocArg)
301 {
302 if (isdigit(c))
303 number.push_back(c);
304 }
305 assert(!number.empty() && "Incorrect naming convention for svf external functions(ALLOC_HEAP_ARG + number)?");
306 return std::stoi(number);
307}
308
309// Does (F) reallocate a new object?
311{
312 return F && hasExtFuncAnnotation(F, "REALLOC_HEAP_RET");
313}
315{
316 assert(F && "Null FunObjVar* pointer");
317 if (F->isDeclaration() || F->isIntrinsic())
318 return true;
319 else if (hasExtFuncAnnotation(F, "OVERWRITE") && getExtFuncAnnotations(F).size() == 1)
320 return false;
321 else
322 return !getExtFuncAnnotations(F).empty();
323}
static std::string GetStdoutFromCommand(const std::string &command)
Definition ExtAPI.cpp:75
static std::string getFilePath(const std::string &path)
Definition ExtAPI.cpp:99
std::string getCurrentSOPath()
Definition ExtAPI.cpp:125
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:288
bool is_arg_alloc(const FunObjVar *F)
Definition ExtAPI.cpp:283
bool is_memcpy(const FunObjVar *F)
Definition ExtAPI.cpp:265
std::string getExtBcPath()
Definition ExtAPI.cpp:136
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:294
static ExtAPI * getExtAPI()
Definition ExtAPI.cpp:44
bool is_ext(const FunObjVar *funObjVar)
Definition ExtAPI.cpp:314
std::string getExtFuncAnnotation(const FunObjVar *fun, const std::string &funcAnnotation)
Definition ExtAPI.cpp:243
bool is_realloc(const FunObjVar *F)
Definition ExtAPI.cpp:310
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:223
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:229
bool is_alloc(const FunObjVar *F)
Definition ExtAPI.cpp:277
const std::vector< std::string > & getExtFuncAnnotations(const FunObjVar *fun)
Definition ExtAPI.cpp:256
bool is_memset(const FunObjVar *F)
Definition ExtAPI.cpp:272
bool isIntrinsic() const
bool isDeclaration() const
static const Option< std::string > ExtAPIPath
Definition Options.h:217
#define NULL
Definition extapi.c:5
char * fgets(char *str, int n, void *stream)
Definition extapi.c:832
int isdigit(int c)
Definition extapi.c:937
char * getenv(const char *name)
Definition extapi.c:1135
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
for isBitcode
Definition BasicTypes.h:68
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74
signed s32_t
Definition GeneralType.h:48