SVF
CPPUtil.cpp
Go to the documentation of this file.
1 //===- CPPUtil.cpp -- Base class of pointer analyses -------------------------//
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 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 General Public License for more details.
17 
18 // You should have received a copy of the GNU General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 //
21 //===----------------------------------------------------------------------===//
22 
23 /*
24  * CPPUtil.cpp
25  *
26  * Created on: Apr 13, 2016
27  * Author: Xiaokang Fan
28  */
29 
30 #include "SVF-FE/CPPUtil.h"
31 #include "Util/SVFUtil.h"
32 #include "SVF-FE/LLVMUtil.h"
33 
34 
35 #include <cxxabi.h> // for demangling
36 
37 using namespace std;
38 using namespace SVF;
39 
40 // label for global vtbl value before demangle
41 const string vtblLabelBeforeDemangle = "_ZTV";
42 
43 // label for global vtbl value before demangle
44 const string vtblLabelAfterDemangle = "vtable for ";
45 
46 // label for virtual functions
47 const string vfunPreLabel = "_Z";
48 
49 // label for multi inheritance virtual function
50 const string NVThunkFunLabel = "non-virtual thunk to ";
51 const string VThunkFuncLabel = "virtual thunk to ";
52 
53 const string clsName = "class.";
54 const string structName = "struct.";
55 
56 static bool isOperOverload(const string name)
57 {
58  s32_t leftnum = 0, rightnum = 0;
59  string subname = name;
60  size_t leftpos, rightpos;
61  leftpos = subname.find("<");
62  while (leftpos != string::npos)
63  {
64  subname = subname.substr(leftpos+1);
65  leftpos = subname.find("<");
66  leftnum++;
67  }
68  subname = name;
69  rightpos = subname.find(">");
70  while (rightpos != string::npos)
71  {
72  subname = subname.substr(rightpos+1);
73  rightpos = subname.find(">");
74  rightnum++;
75  }
76  if (leftnum != rightnum)
77  {
78  return true;
79  }
80  else
81  {
82  return false;
83  }
84 }
85 
86 static string getBeforeParenthesis(const string &name)
87 {
88  size_t lastRightParen = name.rfind(")");
89  assert(lastRightParen > 0);
90 
91  s32_t paren_num = 1, pos;
92  for (pos = lastRightParen - 1; pos >= 0; pos--)
93  {
94  if (name[pos] == ')')
95  paren_num++;
96  if (name[pos] == '(')
97  paren_num--;
98  if (paren_num == 0)
99  break;
100  }
101  return name.substr(0, pos);
102 }
103 
104 string cppUtil::getBeforeBrackets(const string &name)
105 {
106  if (name[name.size() - 1] != '>')
107  {
108  return name;
109  }
110  s32_t bracket_num = 1, pos;
111  for (pos = name.size() - 2; pos >= 0; pos--)
112  {
113  if (name[pos] == '>')
114  bracket_num++;
115  if (name[pos] == '<')
116  bracket_num--;
117  if (bracket_num == 0)
118  break;
119  }
120  return name.substr(0, pos);
121 }
122 
123 bool cppUtil::isValVtbl(const Value *val)
124 {
125  if (!SVFUtil::isa<GlobalVariable>(val))
126  return false;
127  string valName = val->getName().str();
128  if (valName.compare(0, vtblLabelBeforeDemangle.size(),
130  return true;
131  else
132  return false;
133 }
134 
136  // when handling multi-inheritance,
137  // the compiler may generate thunk functions
138  // to perform `this` pointer adjustment
139  // they are indicated with `virtual thunk to `
140  // and `nun-virtual thunk to`.
141  // if the classname starts with part of a
142  // demangled name starts with
143  // these prefixes, we need to remove the prefix
144  // to get the real class name
145 
146  static vector<string> thunkPrefixes = {VThunkFuncLabel, NVThunkFunLabel};
147  for (unsigned i = 0; i < thunkPrefixes.size(); i++) {
148  auto prefix = thunkPrefixes[i];
149  if (dname.className.size() > prefix.size() &&
150  dname.className.compare(0, prefix.size(), prefix) == 0)
151  {
152  dname.className = dname.className.substr(prefix.size());
153  dname.isThunkFunc = true;
154  return;
155 
156  }
157  }
158 }
159 
160 /*
161  * input: _ZN****
162  * after abi::__cxa_demangle:
163  * namespace::A<...::...>::f<...::...>(...)
164  * ^
165  * delimiter
166  *
167  * step1: getBeforeParenthesis
168  * namespace::A<...::...>::f<...::...>
169  *
170  * step2: getBeforeBrackets
171  * namespace::A<...::...>::f
172  *
173  * step3: find delimiter
174  * namespace::A<...::...>::
175  * ^
176  *
177  * className: namespace::A<...::...>
178  * functionName: f<...::...>
179  */
180 
181 struct cppUtil::DemangledName cppUtil::demangle(const string &name)
182 {
183  struct cppUtil::DemangledName dname;
184  dname.isThunkFunc = false;
185 
186  s32_t status;
187  char *realname = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
188  if (realname == nullptr)
189  {
190  dname.className = "";
191  dname.funcName = "";
192  }
193  else
194  {
195  string realnameStr = string(realname);
196  string beforeParenthesis = getBeforeParenthesis(realnameStr);
197  if (beforeParenthesis.find("::") == string::npos ||
198  isOperOverload(beforeParenthesis))
199  {
200  dname.className = "";
201  dname.funcName = "";
202  }
203  else
204  {
205  string beforeBracket = getBeforeBrackets(beforeParenthesis);
206  size_t colon = beforeBracket.rfind("::");
207  if (colon == string::npos)
208  {
209  dname.className = "";
210  dname.funcName = "";
211  }
212  else
213  {
214  dname.className = beforeParenthesis.substr(0, colon);
215  dname.funcName = beforeParenthesis.substr(colon + 2);
216  }
217  }
218  }
219 
220  handleThunkFunction(dname);
221 
222  return dname;
223 }
224 
225 bool cppUtil::isLoadVtblInst(const LoadInst *loadInst)
226 {
227  const Value *loadSrc = loadInst->getPointerOperand();
228  const Type *valTy = loadSrc->getType();
229  const Type *elemTy = valTy;
230  for (s32_t i = 0; i < 3; ++i)
231  {
232  if (const PointerType *ptrTy = SVFUtil::dyn_cast<PointerType>(elemTy))
233  elemTy = ptrTy->getElementType();
234  else
235  return false;
236  }
237  if (const FunctionType *functy = SVFUtil::dyn_cast<FunctionType>(elemTy))
238  {
239  const Type *paramty = functy->getParamType(0);
240  string className = cppUtil::getClassNameFromType(paramty);
241  if (className.size() > 0)
242  {
243  return true;
244  }
245  }
246  return false;
247 }
248 
249 /*
250  * a virtual callsite follows the following instruction sequence pattern:
251  * %vtable = load this
252  * %vfn = getelementptr %vtable, idx
253  * %x = load %vfn
254  * call %x (this)
255  */
257 {
258  // the callsite must be an indirect one with at least one argument (this ptr)
259  if (cs.getCalledFunction() != nullptr || cs.arg_empty())
260  return false;
261 
262  // When compiled with ctir, we'd be using the DCHG which has its own
263  // virtual annotations.
264  if (LLVMModuleSet::getLLVMModuleSet()->allCTir())
265  {
266  return cs.getInstruction()->getMetadata(cppUtil::ctir::derefMDName) != nullptr;
267  }
268 
269  const Value *vfunc = cs.getCalledValue();
270  if (const LoadInst *vfuncloadinst = SVFUtil::dyn_cast<LoadInst>(vfunc))
271  {
272  const Value *vfuncptr = vfuncloadinst->getPointerOperand();
273  if (const GetElementPtrInst *vfuncptrgepinst =
274  SVFUtil::dyn_cast<GetElementPtrInst>(vfuncptr))
275  {
276  if (vfuncptrgepinst->getNumIndices() != 1)
277  return false;
278  const Value *vtbl = vfuncptrgepinst->getPointerOperand();
279  if (SVFUtil::isa<LoadInst>(vtbl))
280  {
281  return true;
282  }
283  }
284  }
285  return false;
286 }
287 
289  cppUtil::DemangledName dname = cppUtil::demangle(F->getName().str());
290  return dname.isThunkFunc;
291 }
292 
294  const Function *ret = nullptr;
295 
296  for (auto &bb:*F) {
297  for (auto &inst: bb) {
298  if (llvm::isa<CallInst>(inst) || llvm::isa<InvokeInst>(inst)
299  || llvm::isa<CallBrInst>(inst)) {
300  CallSite cs(const_cast<Instruction*>(&inst));
301  // assert(cs.getCalledFunction() &&
302  // "Indirect call detected in thunk func");
303  // assert(ret == nullptr && "multiple callsites in thunk func");
304 
305  ret = cs.getCalledFunction();
306  }
307  }
308  }
309 
310  return ret;
311 }
312 
314 {
315  if (cs.paramHasAttr(0, llvm::Attribute::StructRet))
316  {
317  return cs.getArgument(1);
318  }
319  else
320  {
321  return cs.getArgument(0);
322  }
323 }
324 
337 bool cppUtil::isSameThisPtrInConstructor(const Argument* thisPtr1, const Value* thisPtr2)
338 {
339  if (thisPtr1 == thisPtr2)
340  {
341  return true;
342  }
343  else
344  {
345  for (const User *thisU : thisPtr1->users())
346  {
347  if (const StoreInst *store = SVFUtil::dyn_cast<StoreInst>(thisU))
348  {
349  for (const User *storeU : store->getPointerOperand()->users())
350  {
351  if (const LoadInst *load = SVFUtil::dyn_cast<LoadInst>(storeU))
352  {
353  if(load->getNextNode() && SVFUtil::isa<CastInst>(load->getNextNode()))
354  return SVFUtil::cast<CastInst>(load->getNextNode()) == (thisPtr2->stripPointerCasts());
355  }
356  }
357  }
358  }
359  return false;
360  }
361 }
362 
364 {
365  assert((isConstructor(fun) || isDestructor(fun)) && "not a constructor?");
366  assert(fun->arg_size() >=1 && "argument size >= 1?");
367  const Argument* thisPtr = &*(fun->arg_begin());
368  return thisPtr;
369 }
370 
371 /*
372  * get the ptr "vtable" for a given virtual callsite:
373  * %vtable = load ...
374  * %vfn = getelementptr %vtable, idx
375  * %x = load %vfn
376  * call %x (...)
377  */
379 {
380  const LoadInst *loadInst = SVFUtil::dyn_cast<LoadInst>(cs.getCalledValue());
381  assert(loadInst != nullptr);
382  const Value *vfuncptr = loadInst->getPointerOperand();
383  const GetElementPtrInst *gepInst = SVFUtil::dyn_cast<GetElementPtrInst>(vfuncptr);
384  assert(gepInst != nullptr);
385  const Value *vtbl = gepInst->getPointerOperand();
386  return vtbl;
387 }
388 
390 {
391  const LoadInst *vfuncloadinst = SVFUtil::dyn_cast<LoadInst>(cs.getCalledValue());
392  assert(vfuncloadinst != nullptr);
393  const Value *vfuncptr = vfuncloadinst->getPointerOperand();
394  const GetElementPtrInst *vfuncptrgepinst =
396  User::const_op_iterator oi = vfuncptrgepinst->idx_begin();
397  const ConstantInt *idx = SVFUtil::dyn_cast<ConstantInt>(&(*oi));
398  u64_t idx_value;
399  if (idx == nullptr)
400  {
401  SVFUtil::errs() << "vcall gep idx not constantint\n";
402  idx_value = 0;
403  }
404  else
405  idx_value = idx->getSExtValue();
406  return idx_value;
407 }
408 
410 {
411  string className = "";
412  if (const PointerType *ptrType = SVFUtil::dyn_cast<PointerType>(ty))
413  {
414  const Type *elemType = ptrType->getElementType();
415  if (SVFUtil::isa<StructType>(elemType) &&
416  !((SVFUtil::cast<StructType>(elemType))->isLiteral()))
417  {
418  string elemTypeName = elemType->getStructName().str();
419  if (elemTypeName.compare(0, clsName.size(), clsName) == 0)
420  {
421  className = elemTypeName.substr(clsName.size());
422  }
423  else if (elemTypeName.compare(0, structName.size(), structName) == 0)
424  {
425  className = elemTypeName.substr(structName.size());
426  }
427  }
428  }
429  return className;
430 }
431 
433 {
434  string className = "";
435 
436  string vtblName = value->getName().str();
437  s32_t status;
438  char *realname = abi::__cxa_demangle(vtblName.c_str(), 0, 0, &status);
439  if (realname != nullptr)
440  {
441  string realnameStr = string(realname);
442  if (realnameStr.compare(0, vtblLabelAfterDemangle.size(),
444  {
445  className = realnameStr.substr(vtblLabelAfterDemangle.size());
446  }
447  }
448  return className;
449 }
450 
452 {
453  if (F->isDeclaration())
454  return false;
455  string funcName = F->getName().str();
456  if (funcName.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0)
457  {
458  return false;
459  }
460  struct cppUtil::DemangledName dname = demangle(funcName.c_str());
461  dname.funcName = getBeforeBrackets(dname.funcName);
462  dname.className = getBeforeBrackets(dname.className);
463  size_t colon = dname.className.rfind("::");
464  if (colon == string::npos)
465  {
466  dname.className = getBeforeBrackets(dname.className);
467  }
468  else
469  {
470  dname.className = getBeforeBrackets(dname.className.substr(colon+2));
471  }
472  if (dname.className.size() > 0 && (dname.className.compare(dname.funcName) == 0))
474  return true;
475  else
476  return false;
477 }
478 
480 {
481  if (F->isDeclaration())
482  return false;
483  string funcName = F->getName().str();
484  if (funcName.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0)
485  {
486  return false;
487  }
488  struct cppUtil::DemangledName dname = demangle(funcName.c_str());
489  dname.funcName = getBeforeBrackets(dname.funcName);
490  dname.className = getBeforeBrackets(dname.className);
491  size_t colon = dname.className.rfind("::");
492  if (colon == string::npos)
493  {
494  dname.className = getBeforeBrackets(dname.className);
495  }
496  else
497  {
498  dname.className = getBeforeBrackets(dname.className.substr(colon+2));
499  }
500  if (dname.className.size() > 0 && dname.funcName.size() > 0 &&
501  dname.className.size() + 1 == dname.funcName.size() &&
502  dname.funcName.compare(0, 1, "~") == 0 &&
503  dname.className.compare(dname.funcName.substr(1)) == 0)
504  return true;
505  else
506  return false;
507 }
508 
510 {
511  string thisPtrClassName;
512  Instruction *inst = cs.getInstruction();
513  if (const MDNode *N = inst->getMetadata("VCallPtrType"))
514  {
515  const MDString &mdstr = SVFUtil::cast<MDString>((N->getOperand(0)));
516  thisPtrClassName = mdstr.getString().str();
517  }
518  if (thisPtrClassName.size() == 0)
519  {
520  const Value *thisPtr = getVCallThisPtr(cs);
521  thisPtrClassName = getClassNameFromType(thisPtr->getType());
522  }
523 
524  size_t found = thisPtrClassName.find_last_not_of("0123456789");
525  if (found != string::npos)
526  {
527  if (found != thisPtrClassName.size() - 1 && thisPtrClassName[found] == '.')
528  {
529  return thisPtrClassName.substr(0, found);
530  }
531  }
532 
533  return thisPtrClassName;
534 }
535 
537 {
538  string funName;
539  Instruction *inst = cs.getInstruction();
540  if (const MDNode *N = inst->getMetadata("VCallFunName"))
541  {
542  const MDString &mdstr = SVFUtil::cast<MDString>((N->getOperand(0)));
543  funName = mdstr.getString().str();
544  }
545  return funName;
546 }
547 
548 
549 /*
550  * Is this virtual call inside its own constructor or destructor?
551  */
553 {
554  std::string classNameOfThisPtr = getClassNameOfThisPtr(cs);
555  const Function *func = cs.getCaller();
556  if (isConstructor(func) || isDestructor(func))
557  {
558  struct DemangledName dname = demangle(func->getName().str());
559  if (classNameOfThisPtr.compare(dname.className) == 0)
560  return true;
561  }
562  return false;
563 }
u64_t getVCallIdx(CallSite cs)
Definition: CPPUtil.cpp:389
llvm::MDString MDString
Definition: BasicTypes.h:137
llvm::StoreInst StoreInst
Definition: BasicTypes.h:146
llvm::FunctionType FunctionType
Definition: BasicTypes.h:109
const string vtblLabelAfterDemangle
Definition: CPPUtil.cpp:44
bool isVirtualCallSite(CallSite cs)
Definition: CPPUtil.cpp:256
llvm::Type Type
Definition: BasicTypes.h:75
#define assert(ex)
Definition: util.h:141
llvm::PointerType PointerType
Definition: BasicTypes.h:108
Value * getCalledValue() const
Definition: BasicTypes.h:327
bool isConstructor(const Function *F)
Definition: CPPUtil.cpp:451
bool arg_empty() const
Definition: BasicTypes.h:323
raw_ostream & errs()
Overwrite llvm::errs()
Definition: SVFUtil.h:53
const string structName
Definition: CPPUtil.cpp:54
signed s32_t
Definition: SVFBasicTypes.h:77
CallBase * getInstruction() const
Definition: BasicTypes.h:316
llvm::ConstantInt ConstantInt
Definition: BasicTypes.h:153
std::string getClassNameFromType(const Type *ty)
Definition: CPPUtil.cpp:409
bool isDestructor(const Function *F)
Definition: CPPUtil.cpp:479
const std::string derefMDName
Definition: CPPUtil.h:113
bool isSameThisPtrInConstructor(const Argument *thisPtr1, const Value *thisPtr2)
Definition: CPPUtil.cpp:337
bool isCPPThunkFunction(const Function *F)
Definition: CPPUtil.cpp:288
bool VCallInCtorOrDtor(CallSite cs)
Definition: CPPUtil.cpp:552
static string getBeforeParenthesis(const string &name)
Definition: CPPUtil.cpp:86
const Argument * getConstructorThisPtr(const Function *fun)
Definition: CPPUtil.cpp:363
bool isLoadVtblInst(const LoadInst *loadInst)
Definition: CPPUtil.cpp:225
const Function * getThunkTarget(const Function *F)
Definition: CPPUtil.cpp:293
std::string getClassNameFromVtblObj(const Value *value)
Definition: CPPUtil.cpp:432
Value * getArgument(unsigned ArgNo) const
Definition: BasicTypes.h:318
llvm::Function Function
Definition: BasicTypes.h:76
llvm::Instruction Instruction
Definition: BasicTypes.h:79
const Value * getVCallThisPtr(CallSite cs)
Definition: CPPUtil.cpp:313
static bool isOperOverload(const string name)
Definition: CPPUtil.cpp:56
llvm::Argument Argument
LLVM Aliases and constants.
Definition: BasicTypes.h:122
bool isValVtbl(const Value *val)
Definition: CPPUtil.cpp:123
const string vtblLabelBeforeDemangle
Definition: CPPUtil.cpp:41
llvm::GetElementPtrInst GetElementPtrInst
Definition: BasicTypes.h:149
std::string getBeforeBrackets(const std::string &name)
static void handleThunkFunction(cppUtil::DemangledName &dname)
Definition: CPPUtil.cpp:135
bool paramHasAttr(unsigned ArgNo, llvm::Attribute::AttrKind Kind) const
Definition: BasicTypes.h:330
const string NVThunkFunLabel
Definition: CPPUtil.cpp:50
Function * getCaller() const
Definition: BasicTypes.h:328
const Value * getVCallVtblPtr(CallSite cs)
Definition: CPPUtil.cpp:378
std::string getClassNameOfThisPtr(CallSite cs)
Definition: CPPUtil.cpp:509
Function * getCalledFunction() const
Definition: BasicTypes.h:326
llvm::MDNode MDNode
Definition: BasicTypes.h:138
struct DemangledName demangle(const std::string &name)
for isBitcode
Definition: ContextDDA.h:15
llvm::LoadInst LoadInst
Definition: BasicTypes.h:147
std::string getFunNameOfVCallSite(CallSite cs)
Definition: CPPUtil.cpp:536
const string vfunPreLabel
Definition: CPPUtil.cpp:47
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:343
const string clsName
Definition: CPPUtil.cpp:53
const string VThunkFuncLabel
Definition: CPPUtil.cpp:51
llvm::Value Value
Definition: BasicTypes.h:78
llvm::User User
Definition: BasicTypes.h:86
unsigned long long u64_t
Definition: SVFBasicTypes.h:76