Static Value-Flow Analysis
Loading...
Searching...
No Matches
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 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 * CPPUtil.cpp
25 *
26 * Created on: Apr 13, 2016
27 * Author: Xiaokang Fan
28 */
29
30#include "SVF-LLVM/CppUtil.h"
31#include "SVF-LLVM/BasicTypes.h"
32#include "SVF-LLVM/LLVMUtil.h"
33#include "Util/Casting.h"
34#include "Util/SVFUtil.h"
35#include "SVF-LLVM/LLVMModule.h"
37
38#include "llvm/Demangle/Demangle.h"
39
40using namespace SVF;
41
42// label for global vtbl value before demangle
43const std::string vtblLabelAfterDemangle = "vtable for ";
44
45// label for multi inheritance virtual function
46const std::string NVThunkFunLabel = "non-virtual thunk to ";
47const std::string VThunkFuncLabel = "virtual thunk to ";
48
49// label for global vtbl value before demangle
50const std::string vtblLabelBeforeDemangle = "_ZTV";
51
52// label for virtual functions
53const std::string vfunPreLabel = "_Z";
54
55const std::string clsName = "class.";
56const std::string structName = "struct.";
57const std::string vtableType = "(...)**";
58
59const std::string znwm = "_Znwm";
60const std::string zn1Label = "_ZN1"; // c++ constructor
61const std::string znstLabel = "_ZNSt";
62const std::string znst5Label = "_ZNSt5"; // _ZNSt5dequeIPK1ASaIS2_EE5frontEv -> std::deque<A const*, std::allocator<A const*> >::front()
63const std::string znst12Label = "_ZNSt12"; // _ZNSt12forward_listIPK1ASaIS2_EEC2Ev -> std::forward_list<A const*, std::allocator<A const*> >::forward_list()
64const std::string znst6Label = "_ZNSt6"; // _ZNSt6vectorIP1ASaIS1_EEC2Ev -> std::vector<A*, std::allocator<A*> >::vector()
65const std::string znst7Label = "_ZNSt7"; // _ZNSt7__cxx114listIPK1ASaIS3_EEC2Ev -> std::__cxx11::list<A const*, std::allocator<A const*> >::list()
66const std::string znst14Label = "_ZNSt14"; // _ZNSt14_Fwd_list_baseI1ASaIS0_EEC2Ev -> std::_Fwd_list_base<A, std::allocator<A> >::_Fwd_list_base()
67
68
69const std::string znkstLabel = "_ZNKSt";
70const std::string znkst5Label = "_ZNKSt15_"; // _ZNKSt15_Deque_iteratorIPK1ARS2_PS2_EdeEv -> std::_Deque_iterator<A const*, A const*&, A const**>::operator*() const
71const std::string znkst20Label = "_ZNKSt20_"; // _ZNKSt20_List_const_iteratorIPK1AEdeEv -> std::_List_const_iterator<A const*>::operator*() const
72
73const std::string znkst23Label = "_ZNKSt23_"; // _ZNKSt23_Rb_tree_const_iteratorISt4pairIKi1AEEptEv -> std::_List_const_iterator<A const*>::operator*() const
74
75
76const std::string znkLabel = "_ZNK";
77const std::string znk9Label = "_ZNK9"; // _ZNK9__gnu_cxx17__normal_iteratorIPK1ASt6vectorIS1_SaIS1_EEEdeEv -> __gnu_cxx::__normal_iterator<A const*, std::vector<A, std::allocator<A> > >::operator*() const
78
79const std::string ztilabel = "_ZTI";
80const std::string ztiprefix = "typeinfo for ";
81const std::string dyncast = "__dynamic_cast";
82
83
84static bool isOperOverload(const std::string& name)
85{
86 u32_t leftnum = 0, rightnum = 0;
87 std::string subname = name;
88 size_t leftpos, rightpos;
89 leftpos = subname.find('<');
90 while (leftpos != std::string::npos)
91 {
92 subname = subname.substr(leftpos + 1);
93 leftpos = subname.find('<');
94 leftnum++;
95 }
96 subname = name;
97 rightpos = subname.find('>');
98 while (rightpos != std::string::npos)
99 {
100 subname = subname.substr(rightpos + 1);
101 rightpos = subname.find('>');
102 rightnum++;
103 }
104 return leftnum != rightnum;
105}
106
107static std::string getBeforeParenthesis(const std::string& name)
108{
109 size_t lastRightParen = name.rfind(')');
110 assert(lastRightParen > 0);
111
112 s32_t paren_num = 1, pos;
113 for (pos = lastRightParen - 1; pos >= 0; pos--)
114 {
115 if (name[pos] == ')')
116 paren_num++;
117 if (name[pos] == '(')
118 paren_num--;
119 if (paren_num == 0)
120 break;
121 }
122 return name.substr(0, pos);
123}
124
127std::string cppUtil::getBeforeBrackets(const std::string& name)
128{
129 if (name.empty() || name[name.size() - 1] != '>')
130 {
131 return name;
132 }
133 s32_t bracket_num = 1, pos;
134 for (pos = name.size() - 2; pos >= 0; pos--)
135 {
136 if (name[pos] == '>')
137 bracket_num++;
138 if (name[pos] == '<')
139 bracket_num--;
140 if (bracket_num == 0)
141 break;
142 }
143 return name.substr(0, pos);
144}
145
147{
148 // when handling multi-inheritance,
149 // the compiler may generate thunk functions
150 // to perform `this` pointer adjustment
151 // they are indicated with `virtual thunk to `
152 // and `nun-virtual thunk to`.
153 // if the classname starts with part of a
154 // demangled name starts with
155 // these prefixes, we need to remove the prefix
156 // to get the real class name
157
158 static std::vector<std::string> thunkPrefixes = {VThunkFuncLabel,
160 };
161 for (unsigned i = 0; i < thunkPrefixes.size(); i++)
162 {
163 auto prefix = thunkPrefixes[i];
164 if (dname.className.size() > prefix.size() &&
165 dname.className.compare(0, prefix.size(), prefix) == 0)
166 {
167 dname.className = dname.className.substr(prefix.size());
168 dname.isThunkFunc = true;
169 return;
170 }
171 }
172}
173
174/*
175 * input: _ZN****
176 * after abi::__cxa_demangle:
177 * namespace::A<...::...>::f<...::...>(...)
178 * ^
179 * delimiter
180 *
181 * step1: getBeforeParenthesis
182 * namespace::A<...::...>::f<...::...>
183 *
184 * step2: getBeforeBrackets
185 * namespace::A<...::...>::f
186 *
187 * step3: find delimiter
188 * namespace::A<...::...>::
189 * ^
190 *
191 * className: namespace::A<...::...>
192 * functionName: f<...::...>
193 */
194
195struct cppUtil::DemangledName cppUtil::demangle(const std::string& name)
196{
197 return getCXXABI()->demangle(name);
198}
199
200// Extract class name in parameters
201// e.g., given "WithSemaphore::WithSemaphore(AP_HAL::Semaphore&)", return "AP_HAL::Semaphore"
203{
205 // Lambda to trim whitespace from both ends of a string
206 auto trim = [](std::string& s)
207 {
208 size_t first = s.find_first_not_of(' ');
209 size_t last = s.find_last_not_of(' ');
210 if (first != std::string::npos && last != std::string::npos)
211 {
212 s = s.substr(first, (last - first + 1));
213 }
214 else
215 {
216 s.clear();
217 }
218 };
219
220 // Lambda to remove trailing '*' and '&' characters
221 auto removePointerAndReference = [](std::string& s)
222 {
223 while (!s.empty() && (s.back() == '*' || s.back() == '&'))
224 {
225 s.pop_back();
226 }
227 };
228
229 const std::string realnameStr = llvm::demangle(name);
230 if (realnameStr != name && !realnameStr.empty())
231 {
232 // Find the start and end of the parameter list
233 size_t start = realnameStr.find('(');
234 size_t end = realnameStr.find(')');
235 if (start == std::string::npos || end == std::string::npos || start >= end)
236 {
237 return res; // Return empty set if the format is incorrect
238 }
239
240 // Extract the parameter list
241 std::string paramList = realnameStr.substr(start + 1, end - start - 1);
242
243 // Split the parameter list by commas
244 std::istringstream ss(paramList);
245 std::string param;
246 while (std::getline(ss, param, ','))
247 {
248 trim(param);
249 removePointerAndReference(param);
250 res.insert(param);
251 }
252 }
253 return res;
254}
255
256std::string cppUtil::getClassNameFromVtblObj(const std::string& vtblName)
257{
258 return getCXXABI()->extractClassName(vtblName);
259}
260
262{
264 if (!global || !global->hasInitializer())
265 return nullptr;
266
267 Constant *initializer = SVFUtil::cast<Constant>(global->getOperand(0));
268 const ConstantStruct *vtblStruct = SVFUtil::dyn_cast<ConstantStruct>(initializer);
269 // cir2c emits a flat array rather than Clang's struct of arrays.
270 if (auto *array = SVFUtil::dyn_cast<ConstantArray>(initializer))
271 {
272 if (!array->getType()->getElementType()->isPointerTy())
273 return nullptr;
275 ConstantStruct::getAnon(vtbl->getContext(), {array}));
276 }
277 if (!vtblStruct)
278 return nullptr;
279
280 if (vtblStruct->getNumOperands() == 2 &&
281 SVFUtil::isa<ConstantStruct>(vtblStruct->getOperand(0)) &&
282 vtblStruct->getOperand(1)->getType()->isArrayTy())
283 vtblStruct = SVFUtil::cast<ConstantStruct>(vtblStruct->getOperand(0));
284
285 for (unsigned i = 0; i < vtblStruct->getNumOperands(); ++i)
286 {
287 const ConstantArray *array = SVFUtil::dyn_cast<ConstantArray>(vtblStruct->getOperand(i));
288 if (!array || !array->getType()->getElementType()->isPointerTy())
289 return nullptr;
290 }
291
292 return vtblStruct;
293}
294
295bool cppUtil::isValVtbl(const Value* val)
296{
298 return false;
299 std::string valName = val->getName().str();
300 return getCXXABI(val)->isVtable(valName);
301}
302
303/*
304 * a virtual callsite follows the following instruction sequence pattern:
305 * %vtable = load this
306 * %vfn = getelementptr %vtable, idx
307 * %x = load %vfn
308 * call %x (this)
309 */
311{
312 // the callsite must be an indirect one with at least one argument (this
313 // ptr)
314 if (cs->getCalledFunction() != nullptr || cs->arg_empty())
315 return false;
316
317 // the first argument (this pointer) must be a pointer type and must be a
318 // class name
319 if (cs->getArgOperand(0)->getType()->isPointerTy() == false)
320 return false;
321
322 const Value* vfunc = cs->getCalledOperand();
323 if (const LoadInst* vfuncloadinst = SVFUtil::dyn_cast<LoadInst>(vfunc))
324 {
325 const Value* vfuncptr = vfuncloadinst->getPointerOperand();
326 if (const GetElementPtrInst* vfuncptrgepinst =
328 {
329 if (vfuncptrgepinst->getNumIndices() != 1)
330 return false;
331 const Value* vtbl = vfuncptrgepinst->getPointerOperand();
332 if (SVFUtil::isa<LoadInst>(vtbl))
333 {
334 return true;
335 }
336 }
337 }
338 return false;
339}
340
342{
343 cppUtil::DemangledName dname = cppUtil::demangle(F->getName().str());
344 return dname.isThunkFunc;
345}
346
348{
349 const Function* ret = nullptr;
350
351 for (auto& bb : *F)
352 {
353 for (auto& inst : bb)
354 {
355 if (const CallBase* callbase = SVFUtil::dyn_cast<CallBase>(&inst))
356 {
357 // assert(cs.getCalledFunction() &&
358 // "Indirect call detected in thunk func");
359 // assert(ret == nullptr && "multiple callsites in thunk func");
360
361 ret = callbase->getCalledFunction();
362 }
363 }
364 }
365
366 return ret;
367}
368
370{
371 if (cs->paramHasAttr(0, llvm::Attribute::StructRet))
372 {
373 return cs->getArgOperand(1);
374 }
375 else
376 {
377 return cs->getArgOperand(0);
378 }
379}
380
383static bool isDerivedFromThisPtr(const Argument* thisPtr, const Value* V)
384{
385 V = V->stripPointerCasts();
386 if (V == thisPtr)
387 return true;
388
389 if (const LoadInst* load = SVFUtil::dyn_cast<LoadInst>(V))
390 {
391 if (const AllocaInst* alloca =
392 SVFUtil::dyn_cast<AllocaInst>(load->getPointerOperand()))
393 {
394 for (const User* U : alloca->users())
395 {
396 if (const StoreInst* store = SVFUtil::dyn_cast<StoreInst>(U))
397 {
398 if (store->getPointerOperand() == alloca &&
399 store->getValueOperand()->stripPointerCasts() == thisPtr)
400 return true;
401 }
402 }
403 }
404 }
405 return false;
406}
407
443 const Value* thisPtr2)
444{
445 if (thisPtr1 == thisPtr2)
446 return true;
447
448 const Value* stripped = thisPtr2->stripPointerCasts();
449 if (stripped == thisPtr1)
450 return true;
451
452 // === Opaque pointer: Load from this.addr (Case 2: primary base at O0) ===
453 if (isDerivedFromThisPtr(thisPtr1, stripped))
454 return true;
455
456 // === Opaque pointer: GEP check (Case 3 & 4) ===
458 {
459 if (!isDerivedFromThisPtr(thisPtr1, GEP->getPointerOperand()))
460 return false;
461 // i8 GEP = non-primary base class (Case 3)
462 // struct GEP = member field (Case 4)
463 return GEP->getSourceElementType()->isIntegerTy(8);
464 }
465
466 // === Typed pointer (legacy): store -> load -> bitcast ===
467 for (const Value* thisU : thisPtr1->users())
468 {
469 if (const StoreInst* store = SVFUtil::dyn_cast<StoreInst>(thisU))
470 {
471 for (const Value* storeU : store->getPointerOperand()->users())
472 {
473 if (const LoadInst* load = SVFUtil::dyn_cast<LoadInst>(storeU))
474 {
475 if (load->getNextNode() &&
476 SVFUtil::isa<CastInst>(load->getNextNode()))
477 return SVFUtil::cast<CastInst>(load->getNextNode()) ==
478 (thisPtr2->stripPointerCasts());
479 }
480 }
481 }
482 }
483 return false;
484}
485
487{
488 assert((isConstructor(fun) || isDestructor(fun)) &&
489 "not a constructor?");
490 // We always need at least one argument to return something meaningful.
491 assert(fun->arg_size() >= 1 && "expected at least one argument");
492
493 // If param 0 is sret, 'this' is typically param 1, but be defensive.
494 const bool isStructRet = fun->hasParamAttribute(0, llvm::Attribute::StructRet);
495
496 // Prefer arg1 when sret is present and available; otherwise fall back to arg0.
497 const u32_t thisIdx = (isStructRet && fun->arg_size() >= 2) ? 1 : 0;
498 const Argument* thisPtr = fun->getArg(thisIdx);
499
500 return thisPtr;
501}
502
506{
509 size_t colon = dname.className.rfind("::");
510 if (colon == std::string::npos)
511 {
513 }
514 else
515 {
516 // strip off namespace
517 dname.className =
518 cppUtil::getBeforeBrackets(dname.className.substr(colon + 2));
519 }
520}
521
523{
524 if (F->isDeclaration())
525 return false;
526 std::string funcName = F->getName().str();
527 if (funcName.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0)
528 {
529 return false;
530 }
531 struct cppUtil::DemangledName dname = cppUtil::demangle(funcName.c_str());
532 if (dname.className.size() == 0)
533 {
534 return false;
535 }
538 return dname.className.size() > 0 &&
539 dname.className.compare(dname.funcName) == 0;
540}
541
543{
544 if (F->isDeclaration())
545 return false;
546 std::string funcName = F->getName().str();
547 if (funcName.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0)
548 {
549 return false;
550 }
551 struct cppUtil::DemangledName dname = cppUtil::demangle(funcName.c_str());
552 if (dname.className.size() == 0)
553 {
554 return false;
555 }
557 return (dname.className.size() > 0 && dname.funcName.size() > 0 &&
558 dname.className.size() + 1 == dname.funcName.size() &&
559 dname.funcName.compare(0, 1, "~") == 0 &&
560 dname.className.compare(dname.funcName.substr(1)) == 0);
561}
562
563/*
564 * get the ptr "vtable" for a given virtual callsite:
565 * %vtable = load ...
566 * %vfn = getelementptr %vtable, idx
567 * %x = load %vfn
568 * call %x (...)
569 */
571{
572 const LoadInst* loadInst =
573 SVFUtil::dyn_cast<LoadInst>(cs->getCalledOperand());
574 assert(loadInst != nullptr);
575 const Value* vfuncptr = loadInst->getPointerOperand();
576 const GetElementPtrInst* gepInst =
578 assert(gepInst != nullptr);
579 const Value* vtbl = gepInst->getPointerOperand();
580 return vtbl;
581}
582
583/*
584 * Is this virtual call inside its own constructor or destructor?
585 */
587{
588 Set<std::string> classNameOfThisPtrs = cppUtil::getClassNameOfThisPtr(cs);
589 const Function* func = cs->getCaller();
590 for (const auto &classNameOfThisPtr: classNameOfThisPtrs)
591 {
593 {
594 cppUtil::DemangledName dname = cppUtil::demangle(func->getName().str());
595 if (classNameOfThisPtr.compare(dname.className) == 0)
596 return true;
597 }
598 }
599 return false;
600}
601
603{
604 if(getClassNameFromType(ty).empty()==false)
605 {
606 for(auto it = ty->element_begin(); it!=ty->element_end(); it++)
607 {
608 const std::string& str = LLVMUtil::dumpType(*it);
609 if (str.find(vtableType) != std::string::npos)
610 return true;
611 }
612 }
613 return false;
614}
615
617{
618 std::string className = "";
619 if (!((SVFUtil::cast<StructType>(ty))->isLiteral()))
620 {
621 std::string elemTypeName = ty->getStructName().str();
622 if (elemTypeName.compare(0, clsName.size(), clsName) == 0)
623 {
624 className = elemTypeName.substr(clsName.size());
625 }
626 else if (elemTypeName.compare(0, structName.size(), structName) == 0)
627 {
628 className = elemTypeName.substr(structName.size());
629 }
630 }
631 return className;
632}
633
635{
636 Set<std::string> thisPtrNames;
637 std::string thisPtrClassName = "";
638 if (const MDNode* N = inst->getMetadata("VCallPtrType"))
639 {
640 const MDString* mdstr = SVFUtil::cast<MDString>(N->getOperand(0).get());
641 thisPtrClassName = mdstr->getString().str();
642 }
643 if (thisPtrClassName.size() == 0)
644 {
645 const Value* thisPtr = getVCallThisPtr(inst);
647 thisPtrNames.insert(names.begin(), names.end());
648 }
649
651 std::transform(thisPtrNames.begin(), thisPtrNames.end(), std::inserter(ans, ans.begin()),
652 [](const std::string &thisPtrName) -> std::string
653 {
654 size_t found = thisPtrName.find_last_not_of("0123456789");
655 if (found != std::string::npos)
656 {
657 if (found != thisPtrName.size() - 1 &&
658 thisPtrName[found] == '.')
659 {
660 return thisPtrName.substr(0, found);
661 }
662 }
663 return thisPtrName;
664 });
665 return ans;
666}
667
669{
670 std::string funName;
671 if (const MDNode* N = inst->getMetadata("VCallFunName"))
672 {
673 const MDString* mdstr = SVFUtil::cast<MDString>(N->getOperand(0).get());
674 funName = mdstr->getString().str();
675 }
676 return funName;
677}
678
680{
681 const LoadInst* vfuncloadinst =
682 SVFUtil::dyn_cast<LoadInst>(cs->getCalledOperand());
683 assert(vfuncloadinst != nullptr);
684 const Value* vfuncptr = vfuncloadinst->getPointerOperand();
685 const GetElementPtrInst* vfuncptrgepinst =
687 User::const_op_iterator oi = vfuncptrgepinst->idx_begin();
688 const ConstantInt* idx = SVFUtil::dyn_cast<ConstantInt>(oi->get());
689 s32_t idx_value;
690 if (idx == nullptr)
691 {
692 SVFUtil::errs() << "vcall gep idx not constantint\n";
693 idx_value = 0;
694 }
695 else
696 {
697 idx_value = LLVMUtil::getIntegerValue(idx).first;
698 }
699 return idx_value;
700}
701
706{
708 {
709 if (cppUtil::isValVtbl(v))
710 return false;
711 else if (!v->hasInitializer())
712 {
713 return !v->isExternalLinkage(v->getLinkage());
714 }
715 else
716 {
717 StInfo *stInfo = LLVMModuleSet::getLLVMModuleSet()->getSVFType(v->getInitializer()->getType())->getTypeInfo();
718 const std::vector<const SVFType*> &fields = stInfo->getFlattenFieldTypes();
719 for (std::vector<const SVFType*>::const_iterator it = fields.begin(), eit = fields.end(); it != eit; ++it)
720 {
721 const SVFType* elemTy = *it;
722 assert(!SVFUtil::isa<SVFFunctionType>(elemTy) && "Initializer of a global is a function?");
724 return false;
725 }
726
727 return v->isConstant();
728 }
729 }
731}
732
740{
741 const std::string &name = foo->getName().str();
742 if (isConstructor(foo) || isDestructor(foo))
743 {
744 // c++ constructor or destructor
745 DemangledName demangledName = cppUtil::demangle(name);
746 Set<std::string> clsNameInBrackets =
748 clsNameInBrackets.insert(demangledName.className);
749 return clsNameInBrackets;
750 }
751 else if (isTemplateFunc(foo))
752 {
753 // array index
755 assert(!classNames.empty() && "empty class names?");
756 return classNames;
757 }
758 return {};
759}
760
767std::vector<std::string> findInnermostBrackets(const std::string &input)
768{
769 typedef std::pair<u32_t, u32_t> StEdIdxPair;
770 std::stack<int> stack;
771 std::vector<StEdIdxPair> innerMostPairs;
772 std::vector<bool> used(input.length(), false);
773
774 for (u32_t i = 0; i < input.length(); ++i)
775 {
776 if (input[i] == '<')
777 {
778 stack.push(i);
779 }
780 else if (input[i] == '>' && i > 0 && input[i - 1] != '-')
781 {
782 if (!stack.empty())
783 {
784 int openIndex = stack.top();
785 stack.pop();
786
787 // Check if this pair is innermost
788 bool isInnermost = true;
789 for (u32_t j = openIndex + 1; j < i && isInnermost; ++j)
790 {
791 if (used[j])
792 {
793 isInnermost = false;
794 }
795 }
796
797 if (isInnermost)
798 {
799 innerMostPairs.emplace_back(openIndex, i);
800 used[openIndex] = used[i] = true; // Mark these indices as used
801 }
802 }
803 }
804 }
805 std::vector<std::string> ans(innerMostPairs.size());
806 std::transform(innerMostPairs.begin(), innerMostPairs.end(), ans.begin(), [&input](StEdIdxPair &p) -> std::string
807 {
808 return input.substr(p.first + 1, p.second - p.first - 1);
809 });
810 return ans;
811}
812
818std::string stripWhitespaces(const std::string &str)
819{
820 auto start = std::find_if(str.begin(), str.end(), [](unsigned char ch)
821 {
822 return !std::isspace(ch);
823 });
824 auto end = std::find_if(str.rbegin(), str.rend(), [](unsigned char ch)
825 {
826 return !std::isspace(ch);
827 }).base();
828
829 return (start < end) ? std::string(start, end) : std::string();
830}
831
832std::vector<std::string> splitAndStrip(const std::string &input, char delimiter)
833{
834 std::vector<std::string> tokens;
835 size_t start = 0, end = 0;
836
837 while ((end = input.find(delimiter, start)) != std::string::npos)
838 {
839 tokens.push_back(stripWhitespaces(input.substr(start, end - start)));
840 start = end + 1;
841 }
842
843 tokens.push_back(stripWhitespaces(input.substr(start)));
844
845 return tokens;
846}
847
854{
855 // "std::array<A const*, 2ul>" -> A
856 // "std::queue<A*, std::deque<A*, std::allocator<A*> > >" -> A
857 // __gnu_cxx::__aligned_membuf<std::pair<int const, A> >::_M_ptr() const -> A
859 std::string demangleName = llvm::demangle(oname);
860 std::vector<std::string> innermosts = findInnermostBrackets(demangleName);
861 for (const auto &innermost: innermosts)
862 {
863 const std::vector<std::string> &allstrs = splitAndStrip(innermost, ',');
864 for (const auto &str: allstrs)
865 {
866 size_t spacePos = str.find(' ');
867 if (spacePos != std::string::npos)
868 {
869 // A const* -> A
870 ans.insert(str.substr(0, spacePos));
871 }
872 else
873 {
874 size_t starPos = str.find('*');
875 if (starPos != std::string::npos)
876 // A* -> A
877 ans.insert(str.substr(0, starPos));
878 else
879 ans.insert(str);
880 }
881 }
882 }
883 return ans;
884}
885
886
894{
895 if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(val))
896 {
897 const Function *foo = callBase->getCalledFunction();
898 // indirect call
899 if(!foo) return false;
900 return isConstructor(foo) || isDestructor(foo) || isTemplateFunc(foo) || isDynCast(foo);
901 }
902 else if (const auto *func = SVFUtil::dyn_cast<Function>(val))
903 {
904 return isConstructor(func) || isDestructor(func) || isTemplateFunc(func);
905 }
906 return false;
907}
908
915bool cppUtil::matchesLabel(const std::string &foo, const std::string &label)
916{
917 return foo.compare(0, label.size(), label) == 0;
918}
919
927{
928 const std::string &name = foo->getName().str();
929 bool matchedLabel = matchesLabel(name, znstLabel) || matchesLabel(name, znkstLabel) ||
931 // we exclude "_ZNK6cArray3dupEv" -> cArray::dup() const
932 const std::string &demangledName = llvm::demangle(name);
933 return matchedLabel && demangledName.find('<') != std::string::npos && demangledName.find('>') != std::string::npos;
934}
935
942{
943 return foo->getName().str() == dyncast;
944}
945
952{
953 Value *tgtCast = callBase->getArgOperand(2);
954 const std::string &valueStr = LLVMUtil::dumpValue(tgtCast);
955 u32_t leftPos = valueStr.find(ztilabel);
956 assert(leftPos != (u32_t) std::string::npos && "does not find ZTI for dyncast?");
957 u32_t rightPos = leftPos;
958 while (rightPos < valueStr.size() && valueStr[rightPos] != ' ') rightPos++;
959 const std::string &substr = valueStr.substr(leftPos, rightPos - leftPos);
960 std::string demangleName = llvm::demangle(substr);
961 const std::string &realName = demangleName.substr(ztiprefix.size(),
962 demangleName.size() - ztiprefix.size());
963 assert(realName != "" && "real name for dyncast empty?");
964 return realName;
965}
966
967const Type *cppUtil::cppClsNameToType(const std::string &className)
968{
969 StructType *classTy = StructType::getTypeByName(LLVMModuleSet::getLLVMModuleSet()->getContext(),
971 return classTy ? classTy : LLVMModuleSet::getLLVMModuleSet()->getTypeInference()->ptrType();
972}
973
974namespace SVF
975{
976namespace cppUtil
977{
978
980{
981 if (M)
982 {
983 llvm::Triple triple(M->getTargetTriple());
984 if (triple.isKnownWindowsMSVCEnvironment() ||
985 triple.isOSBinFormatCOFF())
986 {
987 static MSVCABI msvcabi;
988 return &msvcabi;
989 }
990 }
991 static ItaniumABI itaniumabi;
992 return &itaniumabi;
993}
994
996{
997 if (val)
998 {
999 if (const GlobalValue* GV = SVFUtil::dyn_cast<GlobalValue>(val))
1000 {
1001 return getCXXABI(GV->getParent());
1002 }
1003 if (const Instruction* I = SVFUtil::dyn_cast<Instruction>(val))
1004 {
1005 return getCXXABI(I->getFunction()->getParent());
1006 }
1007 if (const Argument* Arg = SVFUtil::dyn_cast<Argument>(val))
1008 {
1009 return getCXXABI(Arg->getParent()->getParent());
1010 }
1011 }
1012 return getCXXABI();
1013}
1014
1016{
1019 {
1020 return getCXXABI(
1021 LLVMModuleSet::getLLVMModuleSet()->getMainLLVMModule());
1022 }
1023 static ItaniumABI itaniumabi;
1024 return &itaniumabi;
1025}
1026
1027bool ItaniumABI::isVtable(const std::string& name)
1028{
1029 return name.compare(0, vtblLabelBeforeDemangle.size(),
1031}
1032
1033bool ItaniumABI::isTypeInfo(const std::string& name)
1034{
1035 return name.compare(0, ztilabel.size(), ztilabel) == 0;
1036}
1037
1038bool ItaniumABI::isConstructor(const std::string& name)
1039{
1040 if (name.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0)
1041 {
1042 return false;
1043 }
1045 if (dname.className.size() == 0)
1046 {
1047 return false;
1048 }
1050 return dname.className.size() > 0 && dname.className == dname.funcName;
1051}
1052
1053bool ItaniumABI::isDestructor(const std::string& name)
1054{
1055 if (name.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0)
1056 {
1057 return false;
1058 }
1060 if (dname.className.size() == 0)
1061 {
1062 return false;
1063 }
1065 return (dname.className.size() > 0 && dname.funcName.size() > 0 &&
1066 dname.className.size() + 1 == dname.funcName.size() &&
1067 dname.funcName.compare(0, 1, "~") == 0 &&
1068 dname.className.compare(dname.funcName.substr(1)) == 0);
1069}
1070
1071std::string ItaniumABI::extractClassName(const std::string& name)
1072{
1073 std::string className = "";
1074 std::string realnameStr = llvm::demangle(name);
1075 if (realnameStr != name)
1076 {
1077 if (realnameStr.compare(0, vtblLabelAfterDemangle.size(),
1079 {
1080 className = realnameStr.substr(vtblLabelAfterDemangle.size());
1081 }
1082 }
1083 return className;
1084}
1085
1087{
1088 DemangledName dname;
1089 dname.isThunkFunc = false;
1090
1091 std::string realnameStr = llvm::demangle(name);
1092 if (realnameStr == name)
1093 {
1094 dname.className = "";
1095 dname.funcName = "";
1096 }
1097 else
1098 {
1099 std::string beforeParenthesis = getBeforeParenthesis(realnameStr);
1100 if (beforeParenthesis.find("::") == std::string::npos ||
1101 isOperOverload(beforeParenthesis))
1102 {
1103 dname.className = "";
1104 dname.funcName = "";
1105 }
1106 else
1107 {
1108 std::string beforeBracket = getBeforeBrackets(beforeParenthesis);
1109 size_t colon = beforeBracket.rfind("::");
1110 if (colon == std::string::npos)
1111 {
1112 dname.className = "";
1113 dname.funcName = "";
1114 }
1115 else
1116 {
1117 dname.className = beforeParenthesis.substr(0, colon);
1118 dname.funcName = beforeParenthesis.substr(colon + 2);
1119 }
1120 }
1121 }
1122
1123 handleThunkFunction(dname);
1124
1125 return dname;
1126}
1127
1128bool MSVCABI::isVtable(const std::string& name)
1129{
1130 return name.compare(0, 4, "??_7") == 0 || name.compare(0, 4, "??_8") == 0;
1131}
1132
1133bool MSVCABI::isTypeInfo(const std::string& name)
1134{
1135 return name.compare(0, 4, "??_R") == 0;
1136}
1137
1138bool MSVCABI::isConstructor(const std::string& name)
1139{
1140 return name.compare(0, 3, "??0") == 0;
1141}
1142
1143bool MSVCABI::isDestructor(const std::string& name)
1144{
1145 return name.compare(0, 3, "??1") == 0;
1146}
1147
1148std::string MSVCABI::extractClassName(const std::string& name)
1149{
1150 std::string className = "";
1151 std::string realnameStr = llvm::demangle(name);
1152 size_t pos = realnameStr.rfind("::`vftable'");
1153 if (pos == std::string::npos)
1154 {
1155 pos = realnameStr.rfind("::`vbtable'");
1156 }
1157 if (pos != std::string::npos)
1158 {
1159 className = realnameStr.substr(0, pos);
1160 if (className.compare(0, 6, "const ") == 0)
1161 {
1162 className = className.substr(6);
1163 }
1164 }
1165 return className;
1166}
1167
1169{
1170 DemangledName dname;
1171 dname.isThunkFunc = false;
1172
1173 std::string realnameStr = llvm::demangle(name);
1174 if (realnameStr == name)
1175 {
1176 dname.className = "";
1177 dname.funcName = "";
1178 return dname;
1179 }
1180
1181 if (realnameStr.find("[thunk]") != std::string::npos ||
1182 realnameStr.find("`vcall'") != std::string::npos ||
1183 realnameStr.find("`adjustor'") != std::string::npos)
1184 {
1185 dname.isThunkFunc = true;
1186 }
1187
1188 std::string beforeParenthesis = getBeforeParenthesis(realnameStr);
1189 if (beforeParenthesis.find("::") == std::string::npos ||
1190 isOperOverload(beforeParenthesis))
1191 {
1192 dname.className = "";
1193 dname.funcName = "";
1194 }
1195 else
1196 {
1197 std::string beforeBracket = getBeforeBrackets(beforeParenthesis);
1198 size_t colon = beforeBracket.rfind("::");
1199 if (colon == std::string::npos)
1200 {
1201 dname.className = "";
1202 dname.funcName = "";
1203 }
1204 else
1205 {
1206 std::string classNamePart = beforeParenthesis.substr(0, colon);
1207 dname.funcName = beforeParenthesis.substr(colon + 2);
1208
1209 int i = classNamePart.size() - 1;
1210 int bracketDepth = 0;
1211 while (i >= 0)
1212 {
1213 char c = classNamePart[i];
1214 if (c == '>')
1215 {
1216 bracketDepth++;
1217 }
1218 else if (c == '<')
1219 {
1220 bracketDepth--;
1221 }
1222
1223 if (bracketDepth > 0)
1224 {
1225 i--;
1226 }
1227 else
1228 {
1229 if (std::isalnum(c) || c == '_' || c == ':' || c == '<' ||
1230 c == '>')
1231 {
1232 i--;
1233 }
1234 else
1235 {
1236 break;
1237 }
1238 }
1239 }
1240 dname.className = classNamePart.substr(i + 1);
1241 }
1242 }
1243
1244 return dname;
1245}
1246
1247} // namespace cppUtil
1248} // namespace SVF
PRIVATE Xlinker stack
unsigned u32_t
Definition CommandLine.h:18
const std::string znst6Label
Definition CppUtil.cpp:64
const std::string znkst23Label
Definition CppUtil.cpp:73
const std::string vtblLabelBeforeDemangle
Definition CppUtil.cpp:50
static void handleThunkFunction(cppUtil::DemangledName &dname)
Definition CppUtil.cpp:146
static bool isOperOverload(const std::string &name)
Definition CppUtil.cpp:84
const std::string VThunkFuncLabel
Definition CppUtil.cpp:47
static std::string getBeforeParenthesis(const std::string &name)
Definition CppUtil.cpp:107
const std::string znkst20Label
Definition CppUtil.cpp:71
const std::string znst5Label
Definition CppUtil.cpp:62
const std::string vtblLabelAfterDemangle
Definition CppUtil.cpp:43
static bool isDerivedFromThisPtr(const Argument *thisPtr, const Value *V)
Definition CppUtil.cpp:383
const std::string clsName
Definition CppUtil.cpp:55
const std::string structName
Definition CppUtil.cpp:56
const std::string znstLabel
Definition CppUtil.cpp:61
std::string stripWhitespaces(const std::string &str)
Definition CppUtil.cpp:818
const std::string zn1Label
Definition CppUtil.cpp:60
std::vector< std::string > findInnermostBrackets(const std::string &input)
Definition CppUtil.cpp:767
const std::string znkstLabel
Definition CppUtil.cpp:69
const std::string znst7Label
Definition CppUtil.cpp:65
const std::string dyncast
Definition CppUtil.cpp:81
const std::string znst12Label
Definition CppUtil.cpp:63
const std::string znwm
Definition CppUtil.cpp:59
const std::string NVThunkFunLabel
Definition CppUtil.cpp:46
const std::string znkLabel
Definition CppUtil.cpp:76
const std::string vtableType
Definition CppUtil.cpp:57
const std::string ztilabel
Definition CppUtil.cpp:79
std::vector< std::string > splitAndStrip(const std::string &input, char delimiter)
Definition CppUtil.cpp:832
const std::string znst14Label
Definition CppUtil.cpp:66
const std::string znk9Label
Definition CppUtil.cpp:77
const std::string znkst5Label
Definition CppUtil.cpp:70
void stripBracketsAndNamespace(cppUtil::DemangledName &dname)
Definition CppUtil.cpp:505
const std::string ztiprefix
Definition CppUtil.cpp:80
const std::string vfunPreLabel
Definition CppUtil.cpp:53
cJSON * p
Definition cJSON.cpp:2559
const char *const name
Definition cJSON.h:264
static LLVMModuleSet * getLLVMModuleSet()
Definition LLVMModule.h:137
SVFType * getSVFType(const Type *T)
Get or create SVFType and typeinfo.
ObjTypeInference * getTypeInference()
Set< std::string > & inferThisPtrClsName(const Value *thisPtr)
get or infer the class names of thisptr
const Type * ptrType()
pointer type
StInfo * getTypeInfo()
Definition SVFType.h:273
std::vector< const SVFType * > & getFlattenFieldTypes()
Definition SVFType.h:131
virtual DemangledName demangle(const std::string &name)=0
std::string extractClassName(const std::string &name) override
Definition CppUtil.cpp:1071
bool isVtable(const std::string &name) override
Definition CppUtil.cpp:1027
bool isDestructor(const std::string &name) override
Definition CppUtil.cpp:1053
bool isConstructor(const std::string &name) override
Definition CppUtil.cpp:1038
DemangledName demangle(const std::string &name) override
Definition CppUtil.cpp:1086
bool isTypeInfo(const std::string &name) override
Definition CppUtil.cpp:1033
bool isTypeInfo(const std::string &name) override
Definition CppUtil.cpp:1133
DemangledName demangle(const std::string &name) override
Definition CppUtil.cpp:1168
bool isDestructor(const std::string &name) override
Definition CppUtil.cpp:1143
bool isVtable(const std::string &name) override
Definition CppUtil.cpp:1128
bool isConstructor(const std::string &name) override
Definition CppUtil.cpp:1138
std::string extractClassName(const std::string &name) override
Definition CppUtil.cpp:1148
bool isConstantObjSym(const Value *val)
Check whether this value points-to a constant object.
Definition CppUtil.cpp:705
std::string dumpType(const Type *type)
Definition LLVMUtil.cpp:623
std::pair< s64_t, u64_t > getIntegerValue(const ConstantInt *intValue)
Definition LLVMUtil.h:95
bool isConstDataOrAggData(const Value *val)
Return true if the value refers to constant data, e.g., i32 0.
Definition LLVMUtil.h:397
std::string dumpValue(const Value *val)
Definition LLVMUtil.cpp:612
std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > cast(const Y &Val)
Definition Casting.h:360
LLVM_NODISCARD bool isa(const Y &Val)
Definition Casting.h:241
std::ostream & errs()
Overwrite llvm::errs().
Definition SVFUtil.h:64
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
Definition Casting.h:405
std::string getFunNameOfVCallSite(const CallBase *cs)
Definition CppUtil.cpp:668
std::string getBeforeBrackets(const std::string &name)
Definition CppUtil.cpp:127
const Argument * getConstructorThisPtr(const Function *fun)
Definition CppUtil.cpp:486
std::string extractClsNameFromDynCast(const CallBase *callBase)
extract class name from cpp dyncast function
Definition CppUtil.cpp:951
s32_t getVCallIdx(const CallBase *cs)
Definition CppUtil.cpp:679
const Value * getVCallVtblPtr(const CallBase *cs)
Definition CppUtil.cpp:570
bool isTemplateFunc(const Function *foo)
whether foo is a cpp template function
Definition CppUtil.cpp:926
bool classTyHasVTable(const StructType *ty)
Definition CppUtil.cpp:602
bool isSameThisPtrInConstructor(const Argument *thisPtr1, const Value *thisPtr2)
Definition CppUtil.cpp:442
Set< std::string > getClsNamesInBrackets(const std::string &name)
Definition CppUtil.cpp:202
const Value * getVCallThisPtr(const CallBase *cs)
Definition CppUtil.cpp:369
bool matchesLabel(const std::string &foo, const std::string &label)
whether foo matches the mangler label
Definition CppUtil.cpp:915
std::string getClassNameFromType(const StructType *ty)
Definition CppUtil.cpp:616
struct DemangledName demangle(const std::string &name)
Definition CppUtil.cpp:195
Set< std::string > getClassNameOfThisPtr(const CallBase *cs)
Definition CppUtil.cpp:634
bool isCPPThunkFunction(const Function *F)
Definition CppUtil.cpp:341
bool VCallInCtorOrDtor(const CallBase *cs)
Definition CppUtil.cpp:586
bool isClsNameSource(const Value *val)
Definition CppUtil.cpp:893
CXXABI * getCXXABI()
Definition CppUtil.cpp:1015
Set< std::string > extractClsNamesFromTemplate(const std::string &oname)
extract class names from template functions
Definition CppUtil.cpp:853
bool isVirtualCallSite(const CallBase *cs)
Definition CppUtil.cpp:310
const Type * cppClsNameToType(const std::string &className)
Definition CppUtil.cpp:967
const Function * getThunkTarget(const Function *F)
Definition CppUtil.cpp:347
const ConstantStruct * getVtblStruct(const GlobalValue *vtbl)
Definition CppUtil.cpp:261
bool isConstructor(const Function *F)
Definition CppUtil.cpp:522
std::string getClassNameFromVtblObj(const std::string &vtblName)
Definition CppUtil.cpp:256
Set< std::string > extractClsNamesFromFunc(const Function *foo)
extract class name from the c++ function name, e.g., constructor/destructors
Definition CppUtil.cpp:739
bool isValVtbl(const Value *val)
A carefully crafted input such as FakeVTable _ZTV1A = {{nullptr, nullptr}}; can forge a vtable; detec...
Definition CppUtil.cpp:295
bool isDestructor(const Function *F)
Definition CppUtil.cpp:542
bool isDynCast(const Function *foo)
whether foo is a cpp dyncast function
Definition CppUtil.cpp:941
for isBitcode
Definition BasicTypes.h:70
llvm::GlobalVariable GlobalVariable
Definition BasicTypes.h:131
llvm::Type Type
Definition BasicTypes.h:81
llvm::CallBase CallBase
Definition BasicTypes.h:147
llvm::MDString MDString
Definition BasicTypes.h:99
llvm::ConstantStruct ConstantStruct
Definition BasicTypes.h:104
llvm::StructType StructType
LLVM types.
Definition BasicTypes.h:92
llvm::AllocaInst AllocaInst
Definition BasicTypes.h:151
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition GeneralType.h:51
llvm::Argument Argument
Definition BasicTypes.h:146
llvm::LoadInst LoadInst
Definition BasicTypes.h:150
llvm::ConstantArray ConstantArray
Definition BasicTypes.h:121
llvm::Function Function
Definition BasicTypes.h:83
llvm::GlobalValue GlobalValue
Definition BasicTypes.h:86
llvm::Instruction Instruction
Definition BasicTypes.h:85
llvm::Constant Constant
Definition BasicTypes.h:122
llvm::Value Value
LLVM Basic classes.
Definition BasicTypes.h:80
signed s32_t
Definition GeneralType.h:68
llvm::Module Module
Definition BasicTypes.h:82
llvm::StoreInst StoreInst
Definition BasicTypes.h:149
llvm::GetElementPtrInst GetElementPtrInst
Definition BasicTypes.h:163
llvm::MDNode MDNode
Definition BasicTypes.h:110
unsigned u32_t
Definition GeneralType.h:67
llvm::ConstantInt ConstantInt
Definition BasicTypes.h:123
llvm::User User
Definition BasicTypes.h:143