Static Value-Flow Analysis
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 
37 using namespace SVF;
38 
39 ExtAPI* ExtAPI::extOp = nullptr;
41 
43 {
44  if (extOp == nullptr)
45  {
46  extOp = new ExtAPI;
47  }
48  return extOp;
49 }
50 
52 {
53  if (extOp != nullptr)
54  {
55  delete extOp;
56  extOp = nullptr;
57  }
58 }
59 
60 // Set extapi.bc file path
62 {
63  struct stat statbuf;
64  if (!path.empty() && !stat(path.c_str(), &statbuf))
65  {
66  extBcPath = path;
67  return true;
68  }
69  return false;
70 }
71 
72 // Get environment variables $SVF_DIR and "npm root" through popen() method
74 {
75  char buffer[128];
76  std::string result = "";
77  // Open pipe to file
78  FILE* pipe = popen(command.c_str(), "r");
79  if (!pipe)
80  {
81  return "popen failed!";
82  }
83  // read till end of process:
84  while (!feof(pipe))
85  {
86  // use buffer to read and add to result
87  if (fgets(buffer, 128, pipe) != NULL)
88  result += buffer;
89  }
90  pclose(pipe);
91  // remove "\n"
92  result.erase(remove(result.begin(), result.end(), '\n'), result.end());
93  return result;
94 }
95 
96 // Get extapi.bc file path in npm
97 static std::string getFilePath(const std::string& path)
98 {
99  std::string bcFilePath = "";
100  if (path.compare("SVF_DIR") == 0)
101  {
102  char const* svfdir = getenv("SVF_DIR");
103  if (svfdir)
104  bcFilePath = svfdir;
105  }
106  else if (path.compare("npm root") == 0)
107  {
108  bcFilePath = GetStdoutFromCommand(path);
109  bcFilePath.append("/SVF");
110  }
111 
112  if (!bcFilePath.empty() && bcFilePath.back() != '/')
113  bcFilePath.push_back('/');
114  bcFilePath.append(SVF_BUILD_TYPE "-build").append("/lib/extapi.bc");
115  return bcFilePath;
116 }
117 
118 // Get extapi.bc path
120 {
121  // Default ways of retrieving extapi.bc (in order of precedence):
122  // 1. Set `path/to/extapi.bc` through `setExtBcPath()`
123  // 2. Set `path/to/extapi.bc` through the command line argument `-extapi=path/to/extapi.bc`
124  // 3. Get location generated by CMakeLists.txt from `config.h` header file (if SVF was installed)
125  // 4. Get location in build tree based from `config.h` header file (if SVF was only built)
126  // 5. Get location based on environment variable $ENV{SVF_DIR}
127  // 6. Search for `extapi.bc` from root directory for npm installation (iff SVF installed through npm)
128 
129  // 1. Set `path/to/extapi.bc` through `setExtBcPath()`
130  if (!extBcPath.empty())
131  return extBcPath;
132 
133  // 2. Set `path/to/extapi.bc` through the command line argument `-extapi=path/to/extapi.bc`
135  return extBcPath;
136 
137  // 3. Get location generated by CMakeLists.txt from `config.h` header file (if SVF was installed)
138  if (setExtBcPath(SVF_EXTAPI_BC)) // Full path is available (for custom file names)
139  return extBcPath;
140  if (setExtBcPath(SVF_EXTAPI_DIR "/extapi.bc")) // Based on directory & default filename
141  return extBcPath;
142 
143  // 4. Get location in build tree based from `config.h` header file (if SVF was only built)
144  if (setExtBcPath(SVF_BUILD_DIR "/lib/extapi.bc"))
145  return extBcPath;
146 
147  // 5. Get location based on environment variable $ENV{SVF_DIR}
148  if (setExtBcPath(getFilePath("SVF_DIR")))
149  return extBcPath;
150 
151  // 6. Search for `extapi.bc` from root directory for npm installation (iff SVF installed through npm)
152  if (setExtBcPath(getFilePath("npm root")))
153  return extBcPath;
154 
155  SVFUtil::errs() << "ERROR: Failed to find \"extapi.bc\" LLVM bitcode file in " << extBcPath << std::endl
156  << "To override the default locations for \"extapi.bc\", you can:" << std::endl
157  << "\t1. Use the command line argument \"-extapi=path/to/extapi.bc\"" << std::endl
158  << "\t2. Use the \"setExtBcPath()\" function *BEFORE* calling \"buildSVFModule()\"" << std::endl
159  << "\t3. Override the paths in \"svf/Util/config.h\" (WARNING: will be overwritten when "
160  << "rebuilding SVF (generated by CMakeLists.txt))" << std::endl;
161  abort();
162 }
163 
164 void ExtAPI::setExtFuncAnnotations(const SVFFunction* fun, const std::vector<std::string>& funcAnnotations)
165 {
166  assert(fun && "Null SVFFunction* pointer");
167  func2Annotations[fun] = funcAnnotations;
168 }
169 
170 bool ExtAPI::hasExtFuncAnnotation(const SVFFunction* fun, const std::string& funcAnnotation)
171 {
172  assert(fun && "Null SVFFunction* pointer");
173  auto it = func2Annotations.find(fun);
174  if (it != func2Annotations.end())
175  {
176  for (const std::string& annotation : it->second)
177  if (annotation.find(funcAnnotation) != std::string::npos)
178  return true;
179  }
180  return false;
181 }
182 
184 {
185  assert(fun && "Null SVFFunction* pointer");
186  auto it = func2Annotations.find(fun);
187  if (it != func2Annotations.end())
188  {
189  for (const std::string& annotation : it->second)
190  if (annotation.find(funcAnnotation) != std::string::npos)
191  return annotation;
192  }
193  return "";
194 }
195 
196 const std::vector<std::string>& ExtAPI::getExtFuncAnnotations(const SVFFunction* fun)
197 {
198  assert(fun && "Null SVFFunction* pointer");
199  auto it = func2Annotations.find(fun);
200  if (it != func2Annotations.end())
201  return it->second;
202  return func2Annotations[fun];
203 }
204 
206 {
207  return F &&
208  (hasExtFuncAnnotation(F, "MEMCPY") || hasExtFuncAnnotation(F, "STRCPY")
209  || hasExtFuncAnnotation(F, "STRCAT"));
210 }
211 
213 {
214  return F && hasExtFuncAnnotation(F, "MEMSET");
215 }
216 
218 {
219  return F && hasExtFuncAnnotation(F, "ALLOC_RET");
220 }
221 
222 // Does (F) allocate a new object and assign it to one of its arguments?
224 {
225  return F && hasExtFuncAnnotation(F, "ALLOC_ARG");
226 }
227 
228 // Get the position of argument which holds the new object
230 {
231  std::string allocArg = getExtFuncAnnotation(F, "ALLOC_ARG");
232  assert(!allocArg.empty() && "Not an alloc call via argument or incorrect extern function annotation!");
233 
235  for (char c : allocArg)
236  {
237  if (isdigit(c))
238  number.push_back(c);
239  }
240  assert(!number.empty() && "Incorrect naming convention for svf external functions(ALLOC_ARG + number)?");
241  return std::stoi(number);
242 }
243 
244 // Does (F) reallocate a new object?
246 {
247  return F && hasExtFuncAnnotation(F, "REALLOC_RET");
248 }
249 
250 
251 // Should (F) be considered "external" (either not defined in the program
252 // or a user-defined version of a known alloc or no-op)?
254 {
255  assert(F && "Null SVFFunction* pointer");
256  if (F->isDeclaration() || F->isIntrinsic())
257  return true;
258  else if (hasExtFuncAnnotation(F, "OVERWRITE") && getExtFuncAnnotations(F).size() == 1)
259  return false;
260  else
261  return !getExtFuncAnnotations(F).empty();
262 }
static std::string GetStdoutFromCommand(const std::string &command)
Definition: ExtAPI.cpp:73
static std::string getFilePath(const std::string &path)
Definition: ExtAPI.cpp:97
#define F(f)
return NULL
Definition: cJSON.cpp:1173
char * buffer
Definition: cJSON.h:163
const char *const const double number
Definition: cJSON.h:268
const char *const string
Definition: cJSON.h:172
bool is_alloc(const SVFFunction *F)
Definition: ExtAPI.cpp:217
bool is_arg_alloc(const SVFFunction *F)
Definition: ExtAPI.cpp:223
bool hasExtFuncAnnotation(const SVFFunction *fun, const std::string &funcAnnotation)
Definition: ExtAPI.cpp:170
bool is_ext(const SVFFunction *F)
Definition: ExtAPI.cpp:253
std::string getExtBcPath()
Definition: ExtAPI.cpp:119
const std::vector< std::string > & getExtFuncAnnotations(const SVFFunction *fun)
Definition: ExtAPI.cpp:196
static std::string extBcPath
Definition: ExtAPI.h:55
static ExtAPI * extOp
Definition: ExtAPI.h:49
static ExtAPI * getExtAPI()
Definition: ExtAPI.cpp:42
std::string getExtFuncAnnotation(const SVFFunction *fun, const std::string &funcAnnotation)
Definition: ExtAPI.cpp:183
s32_t get_alloc_arg_pos(const SVFFunction *F)
Definition: ExtAPI.cpp:229
Map< const SVFFunction *, std::vector< std::string > > func2Annotations
Definition: ExtAPI.h:52
bool is_memset(const SVFFunction *F)
Definition: ExtAPI.cpp:212
bool is_memcpy(const SVFFunction *F)
Definition: ExtAPI.cpp:205
ExtAPI()=default
static void destory()
Definition: ExtAPI.cpp:51
static bool setExtBcPath(const std::string &path)
Definition: ExtAPI.cpp:61
bool is_realloc(const SVFFunction *F)
Definition: ExtAPI.cpp:245
void setExtFuncAnnotations(const SVFFunction *fun, const std::vector< std::string > &funcAnnotations)
Definition: ExtAPI.cpp:164
static const Option< std::string > ExtAPIPath
Definition: Options.h:220
int isdigit(int c)
Definition: extapi.c:851
char * fgets(char *str, int n, void *stream)
Definition: extapi.c:746
std::ostream & errs()
Overwrite llvm::errs()
Definition: SVFUtil.h:56
for isBitcode
Definition: BasicTypes.h:68
signed s32_t
Definition: GeneralType.h:47