Static Value-Flow Analysis
Loading...
Searching...
No Matches
ObjTypeInference.cpp
Go to the documentation of this file.
1//===- ObjTypeInference.cpp -- Type inference----------------------------//
2//
3// SVF: Static Value-Flow Analysis
4//
5// Copyright (C) <2013-> <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 * ObjTypeInference.cpp
25 *
26 * Created by Xiao Cheng on 10/01/24.
27 *
28 */
29
31#include "SVF-LLVM/BasicTypes.h"
32#include "SVF-LLVM/LLVMModule.h"
33#include "SVF-LLVM/LLVMUtil.h"
34#include "SVF-LLVM/CppUtil.h"
35#include "Util/Casting.h"
36
37#define TYPE_DEBUG 0 /* Turn this on if you're debugging type inference */
38#define ERR_MSG(msg) \
39 do \
40 { \
41 SVFUtil::errs() << SVFUtil::errMsg("Error ") << __FILE__ << ':' \
42 << __LINE__ << ": " << (msg) << '\n'; \
43 } while (0)
44#define ABORT_MSG(msg) \
45 do \
46 { \
47 ERR_MSG(msg); \
48 abort(); \
49 } while (0)
50#define ABORT_IFNOT(condition, msg) \
51 do \
52 { \
53 if (!(condition)) \
54 ABORT_MSG(msg); \
55 } while (0)
56
57#if TYPE_DEBUG
58#define WARN_MSG(msg) \
59 do \
60 { \
61 SVFUtil::outs() << SVFUtil::wrnMsg("Warning ") << __FILE__ << ':' \
62 << __LINE__ << ": " << msg << '\n'; \
63 } while (0)
64#define WARN_IFNOT(condition, msg) \
65 do \
66 { \
67 if (!(condition)) \
68 WARN_MSG(msg); \
69 } while (0)
70#else
71#define WARN_MSG(msg)
72#define WARN_IFNOT(condition, msg)
73#endif
74
75using namespace SVF;
76using namespace SVFUtil;
77using namespace LLVMUtil;
78using namespace cppUtil;
79
80
81const std::string TYPEMALLOC = "TYPE_MALLOC";
82
86{
87 assert(val && "value cannot be empty");
88 if (SVFUtil::isa<LoadInst, StoreInst>(val))
89 {
90 return llvm::getLoadStoreType(const_cast<Value *>(val));
91 }
92 else if (const auto *gepInst = SVFUtil::dyn_cast<GetElementPtrInst>(val))
93 {
94 return gepInst->getSourceElementType();
95 }
96 else if (const auto *call = SVFUtil::dyn_cast<CallBase>(val))
97 {
98 return call->getFunctionType();
99 }
100 else if (const auto *allocaInst = SVFUtil::dyn_cast<AllocaInst>(val))
101 {
102 return allocaInst->getAllocatedType();
103 }
104 else if (const auto *globalValue = SVFUtil::dyn_cast<GlobalValue>(val))
105 {
106 return globalValue->getValueType();
107 }
108 else
109 {
110 ABORT_MSG("unknown value:" + dumpValueAndDbgInfo(val));
111 }
112}
113
115{
116 ABORT_IFNOT(val, "val cannot be null");
117 // heap has a default type of 8-bit integer type
118 if (SVFUtil::isa<Instruction>(val) && LLVMUtil::isHeapAllocExtCallViaRet(
119 SVFUtil::cast<Instruction>(val)))
120 return int8Type();
121 // otherwise we return a pointer type in the default address space
122 return ptrType();
123}
124
129
137{
138 const Type* res = inferPointsToType(var);
139 // infer type by leveraging the type alignment of src and dst in memcpy
140 // for example,
141 //
142 // %tmp = alloca %struct.outer
143 // %inner_v = alloca %struct.inner
144 // %ptr = getelementptr inbounds %struct.outer, ptr %tmp, i32 0, i32 1, !dbg !38
145 // %0 = load ptr, ptr %ptr, align 8, !dbg !38
146 // call void @llvm.memcpy.p0.p0.i64(ptr %inner_v, ptr %0, i64 24, i1 false)
147 //
148 // It is difficult to infer the type of %0 without deep alias analysis,
149 // but we can infer the obj type of %0 based on that of %inner_v.
150 if (res == defaultType(var))
151 {
152 if (!var->hasUseList()) return res;
153 for (const auto& use: var->users())
154 {
155 if (const CallBase* cs = SVFUtil::dyn_cast<CallBase>(use))
156 {
157 if (const Function* calledFun = cs->getCalledFunction())
159 {
160 assert(cs->getNumOperands() > 1 && "arguments should be greater than 1");
161 const Value* dst = cs->getArgOperand(0);
162 const Value* src = cs->getArgOperand(1);
163 if(calledFun->getName().find("iconv") != std::string::npos)
164 {
165 if(var == cs->getArgOperand(0))
166 return res;
167 dst = cs->getArgOperand(3), src = cs->getArgOperand(1);
168 }
169
170 if (var == dst) return inferPointsToType(src);
171 else if (var == src) return inferPointsToType(dst);
172 else ABORT_MSG("invalid memcpy call");
173 }
174 }
175 }
176 }
177 return res;
178}
179
181{
182 if (isAlloc(var)) return fwInferObjType(var);
185 if (sources.empty())
186 {
187 // cannot find allocation, try to fw infer starting from var
188 types.insert(fwInferObjType(var));
189 }
190 else
191 {
192 for (const auto &source: sources)
193 {
194 types.insert(fwInferObjType(source));
195 }
196 }
198 ABORT_IFNOT(largestTy, "return type cannot be null");
199 return largestTy;
200}
201
207{
208 if (const AllocaInst *allocaInst = SVFUtil::dyn_cast<AllocaInst>(var))
209 {
210 // stack object
212 }
213 else if (const GlobalValue *global = SVFUtil::dyn_cast<GlobalValue>(var))
214 {
215 // global object
216 return infersiteToType(global);
217 }
218 else
219 {
220 // for heap or static object, we forward infer its type
221
222 // consult cache
223 auto tIt = _valueToType.find(var);
224 if (tIt != _valueToType.end())
225 {
226 return tIt->second ? tIt->second : defaultType(var);
227 }
228
229 // simulate the call stack, the second element indicates whether we should update valueTypes for current value
231 Set<ValueBoolPair> visited;
232 workList.push({var, false});
233
234 while (!workList.empty())
235 {
236 auto curPair = workList.pop();
237 if (visited.count(curPair))
238 continue;
239 visited.insert(curPair);
240 const Value* curValue = curPair.first;
241 bool canUpdate = curPair.second;
243
245 &canUpdate](const Value* infersite)
246 {
247 if (canUpdate)
248 infersites.insert(infersite);
249 };
251 [this, &infersites, &workList, &canUpdate](const auto& pUser)
252 {
253 auto vIt = _valueToInferSites.find(pUser);
254 if (canUpdate)
255 {
256 if (vIt != _valueToInferSites.end())
257 {
258 infersites.insert(vIt->second.begin(),
259 vIt->second.end());
260 }
261 }
262 else
263 {
264 if (vIt == _valueToInferSites.end())
265 workList.push({pUser, false});
266 }
267 };
268 if (!canUpdate && !_valueToInferSites.count(curValue))
269 {
270 workList.push({curValue, true});
271 }
272 if (const auto* gepInst =
273 SVFUtil::dyn_cast<GetElementPtrInst>(curValue))
275 if (!curValue->hasUseList()) continue;
276 for (const auto it : curValue->users())
277 {
278 if (const auto* loadInst = SVFUtil::dyn_cast<LoadInst>(it))
279 {
280 /*
281 * infer based on load, e.g.,
282 %call = call i8* malloc()
283 %1 = bitcast i8* %call to %struct.MyStruct*
284 %q = load %struct.MyStruct, %struct.MyStruct* %1
285 */
287 }
288 else if (const auto* storeInst =
289 SVFUtil::dyn_cast<StoreInst>(it))
290 {
291 if (storeInst->getPointerOperand() == curValue)
292 {
293 /*
294 * infer based on store (pointer operand), e.g.,
295 %call = call i8* malloc()
296 %1 = bitcast i8* %call to %struct.MyStruct*
297 store %struct.MyStruct .., %struct.MyStruct* %1
298 */
300 }
301 else
302 {
303 for (const auto nit :
304 storeInst->getPointerOperand()->users())
305 {
306 /*
307 * propagate across store (value operand) and load
308 %call = call i8* malloc()
309 store i8* %call, i8** %p
310 %q = load i8*, i8** %p
311 ..infer based on %q..
312 */
313 if (SVFUtil::isa<LoadInst>(nit))
315 }
316 /*
317 * infer based on store (value operand) <- gep (result element)
318 */
319 if (const auto* gepInst =
320 SVFUtil::dyn_cast<GetElementPtrInst>(
321 storeInst->getPointerOperand()))
322 {
323 /*
324 %call1 = call i8* @TYPE_MALLOC(i32 noundef 16, i32
325 noundef 2), !dbg !39 %2 = bitcast i8* %call1 to
326 %struct.MyStruct*, !dbg !41 %3 = load
327 %struct.MyStruct*, %struct.MyStruct** %p, align 8,
328 !dbg !42 %next = getelementptr inbounds
329 %struct.MyStruct, %struct.MyStruct* %3, i32 0, i32
330 1, !dbg !43 store %struct.MyStruct* %2,
331 %struct.MyStruct** %next, align 8, !dbg !44 %5 =
332 load %struct.MyStruct*, %struct.MyStruct** %p,
333 align 8, !dbg !48 %next3 = getelementptr inbounds
334 %struct.MyStruct, %struct.MyStruct* %5, i32 0, i32
335 1, !dbg !49 %6 = load %struct.MyStruct*,
336 %struct.MyStruct** %next3, align 8, !dbg !49 infer
337 site -> %f1 = getelementptr inbounds
338 %struct.MyStruct, %struct.MyStruct* %6, i32 0, i32
339 0, !dbg !50
340 */
341 const Value* gepBase = gepInst->getPointerOperand();
342 if (const auto* load =
343 SVFUtil::dyn_cast<LoadInst>(gepBase))
344 {
345 for (const auto loadUse :
346 load->getPointerOperand()->users())
347 {
348 if (loadUse == load ||
349 !SVFUtil::isa<LoadInst>(loadUse))
350 continue;
351 for (const auto gepUse : loadUse->users())
352 {
353 if (!SVFUtil::isa<GetElementPtrInst>(
354 gepUse))
355 continue;
356 for (const auto loadUse2 :
357 gepUse->users())
358 {
359 if (SVFUtil::isa<LoadInst>(
360 loadUse2))
361 {
363 loadUse2);
364 }
365 }
366 }
367 }
368 }
369 else if (const auto* alloc =
370 SVFUtil::dyn_cast<AllocaInst>(gepBase))
371 {
372 /*
373 %2 = alloca %struct.ll, align 8
374 store i32 0, ptr %1, align 4
375 %3 = call noalias noundef nonnull ptr
376 @_Znwm(i64 noundef 16) #2 %4 = getelementptr
377 inbounds %struct.ll, ptr %2, i32 0, i32 1
378 store ptr %3, ptr %4, align 8
379 %5 = getelementptr inbounds %struct.ll, ptr
380 %2, i32 0, i32 1 %6 = load ptr, ptr %5, align
381 8 %7 = getelementptr inbounds %struct.ll, ptr
382 %6, i32 0, i32 0
383 */
384 for (const auto gepUse : alloc->users())
385 {
386 if (!SVFUtil::isa<GetElementPtrInst>(
387 gepUse))
388 continue;
389 for (const auto loadUse2 : gepUse->users())
390 {
391 if (SVFUtil::isa<LoadInst>(loadUse2))
392 {
394 loadUse2);
395 }
396 }
397 }
398 }
399 }
400 }
401 }
402 else if (const auto* gepInst =
403 SVFUtil::dyn_cast<GetElementPtrInst>(it))
404 {
405 /*
406 * infer based on gep (pointer operand)
407 %call = call i8* malloc()
408 %1 = bitcast i8* %call to %struct.MyStruct*
409 %next = getelementptr inbounds %struct.MyStruct,
410 %struct.MyStruct* %1, i32 0..
411 */
412 if (gepInst->getPointerOperand() == curValue)
414 }
415 else if (const auto* bitcast =
416 SVFUtil::dyn_cast<BitCastInst>(it))
417 {
418 // continue on bitcast
420 }
421 else if (const auto* phiNode = SVFUtil::dyn_cast<PHINode>(it))
422 {
423 // continue on bitcast
425 }
426 else if (const auto* retInst =
427 SVFUtil::dyn_cast<ReturnInst>(it))
428 {
429 /*
430 * propagate from return to caller
431 Function Attrs: noinline nounwind optnone uwtable
432 define dso_local i8* @malloc_wrapper() #0 !dbg !22 {
433 entry:
434 %call = call i8* @malloc(i32 noundef 16), !dbg !25
435 ret i8* %call, !dbg !26
436 }
437 %call = call i8* @malloc_wrapper()
438 ..infer based on %call..
439 */
440 for (const auto callsite : retInst->getFunction()->users())
441 {
442 if (const auto* callBase =
443 SVFUtil::dyn_cast<CallBase>(callsite))
444 {
445 // skip function as parameter
446 // e.g., call void @foo(%struct.ssl_ctx_st* %9, i32 (i8*, i32, i32, i8*)* @passwd_callback)
447 if (callBase->getCalledFunction() !=
448 retInst->getFunction())
449 continue;
451 }
452 }
453 }
454 else if (const auto* callBase = SVFUtil::dyn_cast<CallBase>(it))
455 {
456 /*
457 * propagate from callsite to callee
458 %call = call i8* @malloc(i32 noundef 16)
459 %0 = bitcast i8* %call to %struct.Node*, !dbg !43
460 call void @foo(%struct.Node* noundef %0), !dbg !45
461
462 define dso_local void @foo(%struct.Node* noundef %param)
463 #0 !dbg !22 {...}
464 ..infer based on the formal param %param..
465 */
466 // skip global function value -> callsite
467 // e.g., def @foo() -> call @foo()
468 // we don't skip function as parameter, e.g., def @foo() -> call @bar(..., @foo)
469 if (SVFUtil::isa<Function>(curValue) &&
470 curValue == callBase->getCalledFunction())
471 continue;
472 // skip indirect call
473 // e.g., %0 = ... -> call %0(...)
474 if (!callBase->hasArgument(curValue))
475 continue;
476 if (Function* calleeFunc = callBase->getCalledFunction())
477 {
479 // for varargs function, we cannot directly get the value-flow between actual and formal args e.g., consider the following vararg function @callee 1: call void @callee(%arg) 2: define dso_local i32 @callee(...) #0 !dbg !17 { 3: ....... 4: %5 = load i32, ptr %vaarg.addr, align 4, !dbg !55 5: .......
480 // 6: }
481 // it is challenging to precisely identify the forward value-flow of %arg (Line 2) because the function definition of callee (Line 2) does not have any formal args related to the actual arg %arg therefore we track all possible instructions like ``load i32, ptr %vaarg.addr''
482 if (calleeFunc->isVarArg())
483 {
484 // conservatively track all var args
485 for (auto& I : instructions(calleeFunc))
486 {
487 if (auto* load =
488 llvm::dyn_cast<llvm::LoadInst>(&I))
489 {
490 llvm::Value* loadPointer =
491 load->getPointerOperand();
492 if (loadPointer->getName().compare(
493 "vaarg.addr") == 0)
494 {
496 }
497 }
498 }
499 }
500 else if (!calleeFunc->isDeclaration())
501 {
503 calleeFunc->getArg(pos));
504 }
505 }
506 }
507 }
508 if (canUpdate)
509 {
511 std::transform(infersites.begin(), infersites.end(),
512 std::inserter(types, types.begin()),
516 }
517 }
518 const Type* type = _valueToType[var];
519 if (type == nullptr)
520 {
522 WARN_MSG("Using default type, trace ID is " +
523 std::to_string(traceId) + ":" + dumpValueAndDbgInfo(var));
524 }
525 ABORT_IFNOT(type, "type cannot be a null ptr");
526 return type;
527 }
528}
529
536{
537
538 // consult cache
539 auto tIt = _valueToAllocs.find(var);
540 if (tIt != _valueToAllocs.end())
541 {
542 return tIt->second;
543 }
544
545 // simulate the call stack, the second element indicates whether we should update sources for current value
547 Set<ValueBoolPair> visited;
548 workList.push({var, false});
549 while (!workList.empty())
550 {
551 auto curPair = workList.pop();
552 if (visited.count(curPair)) continue;
553 visited.insert(curPair);
554 const Value *curValue = curPair.first;
555 bool canUpdate = curPair.second;
556
557 Set<const Value *> sources;
558 auto insertAllocs = [&sources, &canUpdate](const Value *source)
559 {
560 if (canUpdate) sources.insert(source);
561 };
562 auto insertAllocsOrPushWorklist = [this, &sources, &workList, &canUpdate](const auto &pUser)
563 {
564 auto vIt = _valueToAllocs.find(pUser);
565 if (canUpdate)
566 {
567 if (vIt != _valueToAllocs.end())
568 {
569 sources.insert(vIt->second.begin(), vIt->second.end());
570 }
571 }
572 else
573 {
574 if (vIt == _valueToAllocs.end()) workList.push({pUser, false});
575 }
576 };
577
578 if (!canUpdate && !_valueToAllocs.count(curValue))
579 {
580 workList.push({curValue, true});
581 }
582
583 if (isAlloc(curValue))
584 {
586 }
587 else if (const auto *bitCastInst = SVFUtil::dyn_cast<BitCastInst>(curValue))
588 {
589 Value *prevVal = bitCastInst->getOperand(0);
591 }
592 else if (const auto *phiNode = SVFUtil::dyn_cast<PHINode>(curValue))
593 {
594 for (u32_t i = 0; i < phiNode->getNumOperands(); ++i)
595 {
597 }
598 }
599 else if (const auto *loadInst = SVFUtil::dyn_cast<LoadInst>(curValue))
600 {
601 for (const auto use: loadInst->getPointerOperand()->users())
602 {
603 if (const StoreInst *storeInst = SVFUtil::dyn_cast<StoreInst>(use))
604 {
605 if (storeInst->getPointerOperand() == loadInst->getPointerOperand())
606 {
607 insertAllocsOrPushWorklist(storeInst->getValueOperand());
608 }
609 }
610 }
611 }
612 else if (const auto *argument = SVFUtil::dyn_cast<Argument>(curValue))
613 {
614 for (const auto use: argument->getParent()->users())
615 {
616 if (const CallBase *callBase = SVFUtil::dyn_cast<CallBase>(use))
617 {
618 // skip function as parameter
619 // e.g., call void @foo(%struct.ssl_ctx_st* %9, i32 (i8*, i32, i32, i8*)* @passwd_callback)
620 if (callBase->getCalledFunction() != argument->getParent()) continue;
621 u32_t pos = argument->getParent()->isVarArg() ? 0 : argument->getArgNo();
622 insertAllocsOrPushWorklist(callBase->getArgOperand(pos));
623 }
624 }
625 }
626 else if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(curValue))
627 {
628 ABORT_IFNOT(!callBase->doesNotReturn(), "callbase does not return:" + dumpValueAndDbgInfo(callBase));
629 if (Function *callee = callBase->getCalledFunction())
630 {
631 if (!callee->isDeclaration())
632 {
633
635 const BasicBlock* exitBB = llvmmodule->getFunExitBB(callee);
636 assert (exitBB && "exit bb is not a basic block?");
637 const Value *pValue = &exitBB->back();
638 const auto *retInst = SVFUtil::dyn_cast<ReturnInst>(pValue);
639 ABORT_IFNOT(retInst && retInst->getReturnValue(), "not return inst?");
640 insertAllocsOrPushWorklist(retInst->getReturnValue());
641 }
642 }
643 }
644 if (canUpdate)
645 {
647 }
648 }
649 Set<const Value *> &srcs = _valueToAllocs[var];
650 if (srcs.empty())
651 {
652 WARN_MSG("Cannot find allocation: " + dumpValueAndDbgInfo(var));
653 }
654 return srcs;
655}
656
661
667{
668 if (const Function *func = cs->getCalledFunction())
669 {
670 if (func->getName().find(TYPEMALLOC) != std::string::npos)
671 {
672 const Type *objType = fwInferObjType(cs);
673 const auto *pInt =
674 SVFUtil::dyn_cast<llvm::ConstantInt>(cs->getOperand(1));
675 assert(pInt && "the second argument is a integer");
678 SVFUtil::outs() << SVFUtil::sucMsg("\t SUCCESS :") << dumpValueAndDbgInfo(cs)
679 << SVFUtil::pasMsg(" TYPE: ")
680 << dumpType(objType) << "\n";
681 else
682 {
683 SVFUtil::errs() << SVFUtil::errMsg("\t FAILURE :") << ":" << dumpValueAndDbgInfo(cs) << " TYPE: "
684 << dumpType(objType) << "\n";
685 abort();
686 }
687 }
688 }
689}
690
692{
693#if TYPE_DEBUG
697 {
698 ERR_MSG("original type is:" + dumpType(oTy));
699 ERR_MSG("infered type is:" + dumpType(iTy));
700 ABORT_MSG("wrong type, trace ID is " + std::to_string(traceId) + ":" + dumpValueAndDbgInfo(val));
701 }
702#endif
703}
704
706{
707 assert(callBase->hasArgument(arg) && "callInst does not have argument arg?");
708 auto it = std::find(callBase->arg_begin(), callBase->arg_end(), arg);
709 assert(it != callBase->arg_end() && "Didn't find argument?");
710 return std::distance(callBase->arg_begin(), it);
711}
712
713
715{
716 if (objTys.empty()) return nullptr;
717 // map type size to types from with key in descending order
719 for (const Type *ty: objTys)
720 {
722 }
723 assert(!typeSzToTypes.empty() && "typeSzToTypes cannot be empty");
725 std::tie(std::ignore, largestTypes) = *typeSzToTypes.begin();
726 assert(!largestTypes.empty() && "largest element cannot be empty");
727 return *largestTypes.begin();
728}
729
731{
733 if (SVFUtil::isa<ArrayType>(objTy))
735 else if (const auto *st = SVFUtil::dyn_cast<StructType>(objTy))
736 {
739 if (!classTyHasVTable(st))
741 }
742 return num;
743}
744
745
756{
757 auto it = _thisPtrClassNames.find(thisPtr);
758 if (it != _thisPtrClassNames.end()) return it->second;
759
761
762 // Lambda for checking a function is a valid name source & extracting a class name from it
763 auto addNamesFromFunc = [&names](const Function *func) -> void
764 {
765 ABORT_IFNOT(isClsNameSource(func), "Func is invalid class name source: " + dumpValueAndDbgInfo(func));
766 for (const auto &name : extractClsNamesFromFunc(func)) names.insert(name);
767 };
768
769 // Lambda for getting callee & extracting class name for calls to constructors/destructors/template funcs
770 auto addNamesFromCall = [&names, &addNamesFromFunc](const CallBase *call) -> void
771 {
772 ABORT_IFNOT(isClsNameSource(call), "Call is invalid class name source: " + dumpValueAndDbgInfo(call));
773
774 const auto *func = call->getCalledFunction();
775 if (isDynCast(func)) names.insert(extractClsNameFromDynCast(call));
777 };
778
779 // Walk backwards to find all valid source sites for the pointer (e.g. stack/global/heap variables)
780 for (const auto &val: bwFindAllocOrClsNameSources(thisPtr))
781 {
782 // A source site is either a constructor/destructor/template function from which the class name can be
783 // extracted; a call to a C++ constructor/destructor/template function from which the class name can be
784 // extracted; or an allocation site of an object (i.e. a stack/global/heap variable), from which a
785 // forward walk can be performed to find calls to C++ constructor/destructor/template functions from
786 // which the class' name can then be extracted; skip starting pointer
787 if (val == thisPtr) continue;
788
789 if (const auto *func = SVFUtil::dyn_cast<Function>(val))
790 {
791 // Constructor/destructor/template func; extract name from func directly
793 }
794 else if (isClsNameSource(val))
795 {
796 // Call to constructor/destructor/template func; get callee; extract name from callee
797 ABORT_IFNOT(SVFUtil::isa<CallBase>(val), "Call source site is not a callbase: " + dumpValueAndDbgInfo(val));
798 addNamesFromCall(SVFUtil::cast<CallBase>(val));
799 }
800 else if (isAlloc(val))
801 {
802 // Stack/global/heap allocation site; walk forward; find constructor/destructor/template calls
803 ABORT_IFNOT((SVFUtil::isa<AllocaInst, CallBase, GlobalVariable>(val)),
804 "Alloc site source is not a stack/heap/global variable: " + dumpValueAndDbgInfo(val));
805 for (const auto *src : fwFindClsNameSources(val))
806 {
807 if (const auto *func = SVFUtil::dyn_cast<Function>(src)) addNamesFromFunc(func);
808 else if (const auto *call = SVFUtil::dyn_cast<CallBase>(src)) addNamesFromCall(call);
809 else ABORT_MSG("Source site from forward walk is invalid: " + dumpValueAndDbgInfo(src));
810 }
811 }
812 else
813 {
814 ERR_MSG("Unsupported source type found:" + dumpValueAndDbgInfo(val));
815 }
816 }
817
819}
820
829{
830
831 // consult cache
834 {
835 return tIt->second;
836 }
837
838 // simulate the call stack, the second element indicates whether we should update sources for current value
840 Set<ValueBoolPair> visited;
841 workList.push({startValue, false});
842 while (!workList.empty())
843 {
844 auto curPair = workList.pop();
845 if (visited.count(curPair)) continue;
846 visited.insert(curPair);
847 const Value *curValue = curPair.first;
848 bool canUpdate = curPair.second;
849
850 Set<const Value *> sources;
851 auto insertSource = [&sources, &canUpdate](const Value *source)
852 {
853 if (canUpdate) sources.insert(source);
854 };
855 auto insertSourcesOrPushWorklist = [this, &sources, &workList, &canUpdate](const auto &pUser)
856 {
858 if (canUpdate)
859 {
860 if (vIt != _valueToAllocOrClsNameSources.end() && !vIt->second.empty())
861 {
862 sources.insert(vIt->second.begin(), vIt->second.end());
863 }
864 }
865 else
866 {
867 if (vIt == _valueToAllocOrClsNameSources.end()) workList.push({pUser, false});
868 }
869 };
870
872 {
873 workList.push({curValue, true});
874 }
875
876 // If current value is an instruction inside a constructor/destructor/template, use it as a source
877 if (const auto *inst = SVFUtil::dyn_cast<Instruction>(curValue))
878 {
879 if (const auto *parent = inst->getFunction())
880 {
882 }
883 }
884
885 // If the current value is an object (global, heap, stack, etc) or name source (constructor/destructor,
886 // a C++ dynamic cast, or a template function), use it as a source
888 {
890 }
891
892 // Explore the current value further depending on the type of the value; use cached values if possible
893 if (const auto *getElementPtrInst = SVFUtil::dyn_cast<GetElementPtrInst>(curValue))
894 {
896 }
897 else if (const auto *bitCastInst = SVFUtil::dyn_cast<BitCastInst>(curValue))
898 {
900 }
901 else if (const auto *phiNode = SVFUtil::dyn_cast<PHINode>(curValue))
902 {
903 for (const auto *op : phiNode->operand_values())
904 {
906 }
907 }
908 else if (const auto *loadInst = SVFUtil::dyn_cast<LoadInst>(curValue))
909 {
910 for (const auto *user : loadInst->getPointerOperand()->users())
911 {
912 if (const auto *storeInst = SVFUtil::dyn_cast<StoreInst>(user))
913 {
914 if (storeInst->getPointerOperand() == loadInst->getPointerOperand())
915 {
916 insertSourcesOrPushWorklist(storeInst->getValueOperand());
917 }
918 }
919 }
920 }
921 else if (const auto *argument = SVFUtil::dyn_cast<Argument>(curValue))
922 {
923 for (const auto *user: argument->getParent()->users())
924 {
925 if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(user))
926 {
927 // skip function as parameter
928 // e.g., call void @foo(%struct.ssl_ctx_st* %9, i32 (i8*, i32, i32, i8*)* @passwd_callback)
929 if (callBase->getCalledFunction() != argument->getParent()) continue;
930 u32_t pos = argument->getParent()->isVarArg() ? 0 : argument->getArgNo();
932 }
933 }
934 }
935 else if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(curValue))
936 {
937 ABORT_IFNOT(!callBase->doesNotReturn(), "callbase does not return:" + dumpValueAndDbgInfo(callBase));
938 if (const auto *callee = callBase->getCalledFunction())
939 {
940 if (!callee->isDeclaration())
941 {
943 const BasicBlock* exitBB = llvmmodule->getFunExitBB(callee);
944 assert (exitBB && "exit bb is not a basic block?");
945 const Value *pValue = &exitBB->back();
946 const auto *retInst = SVFUtil::dyn_cast<ReturnInst>(pValue);
947 ABORT_IFNOT(retInst && retInst->getReturnValue(), "not return inst?");
948 insertSourcesOrPushWorklist(retInst->getReturnValue());
949 }
950 }
951 }
952
953 // If updating is allowed; store the gathered sources as sources for the current value in the cache
954 if (canUpdate)
955 {
957 }
958 }
959
960 return _valueToAllocOrClsNameSources[startValue];
961}
962
964{
965 assert(startValue && "startValue was null?");
966
967 // consult cache
969 if (tIt != _objToClsNameSources.end())
970 {
971 return tIt->second;
972 }
973
974 Set<const CallBase *> sources;
975
976 // Lambda for adding a callee to the sources iff it is a constructor/destructor/template/dyncast
977 auto inferViaCppCall = [&sources](const CallBase *caller)
978 {
979 if (!caller) return;
980 if (isClsNameSource(caller)) sources.insert(caller);
981 };
982
983 // Find all calls of starting val (or through cast); add as potential source iff applicable
984 for (const auto *user : startValue->users())
985 {
986 if (const auto *caller = SVFUtil::dyn_cast<CallBase>(user))
987 {
989 }
990 else if (const auto *bitcast = SVFUtil::dyn_cast<BitCastInst>(user))
991 {
992 for (const auto *cast_user : bitcast->users())
993 {
994 if (const auto *caller = SVFUtil::dyn_cast<CallBase>(cast_user))
995 {
997 }
998 }
999 }
1000 }
1001
1002 // Store sources in cache for starting value & return the found sources
1004}
#define ABORT_MSG(msg)
const std::string TYPEMALLOC
const Type * infersiteToType(const Value *val)
#define ABORT_IFNOT(condition, msg)
#define ERR_MSG(msg)
#define WARN_MSG(msg)
newitem type
Definition cJSON.cpp:2739
const char *const name
Definition cJSON.h:264
static LLVMModuleSet * getLLVMModuleSet()
Definition LLVMModule.h:131
LLVMContext & getContext() const
Definition LLVMModule.h:382
ValueToInferSites _valueToInferSites
ValueToSources _valueToAllocs
const Type * selectLargestSizedType(Set< const Type * > &objTys)
select the largest (conservative) type from all types
const Type * inferPointsToType(const Value *var)
Set< const Value * > & bwfindAllocOfVar(const Value *var)
backward collect all possible allocation sites (stack, static, heap) of var
u32_t objTyToNumFields(const Type *objTy)
bool isAlloc(const SVF::Value *val)
is allocation (stack, static, heap)
u32_t getArgPosInCall(const CallBase *callBase, const Value *arg)
Set< const Value * > & bwFindAllocOrClsNameSources(const Value *startValue)
ValueToClassNames _thisPtrClassNames
Set< std::string > & inferThisPtrClsName(const Value *thisPtr)
get or infer the class names of thisptr
void typeSizeDiffTest(const PointerType *oPTy, const Type *iTy, const Value *val)
const Type * fwInferObjType(const Value *var)
forward infer the type of the object pointed by var
const IntegerType * int8Type()
int8 type
const Type * ptrType()
pointer type
const Type * inferObjType(const Value *var)
get or infer the type of the object pointed by the value
const Type * defaultType(const Value *val)
default type
ObjToClsNameSources _objToClsNameSources
Set< const CallBase * > & fwFindClsNameSources(const Value *startValue)
forward find class name sources starting from an allocation
void validateTypeCheck(const CallBase *cs)
validate type inference
ValueToSources _valueToAllocOrClsNameSources
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition Options.h:35
bool isHeapAllocExtCallViaRet(const Instruction *inst)
Definition LLVMUtil.cpp:638
bool isMemcpyExtFun(const Function *fun)
Definition LLVMUtil.cpp:389
std::string dumpType(const Type *type)
Definition LLVMUtil.cpp:616
std::pair< s64_t, u64_t > getIntegerValue(const ConstantInt *intValue)
Definition LLVMUtil.h:83
std::string dumpValueAndDbgInfo(const Value *val)
Definition LLVMUtil.cpp:627
u32_t getNumOfElements(const Type *ety)
Return size of this object based on LLVM value.
Definition LLVMUtil.cpp:296
bool isObject(const Value *ref)
Return true if this value refers to a object.
Definition LLVMUtil.cpp:60
static Type * getPtrElementType(const PointerType *pty)
Definition LLVMUtil.h:132
std::string sucMsg(const std::string &msg)
Returns successful message by converting a string into green string output.
Definition SVFUtil.cpp:55
std::string pasMsg(const std::string &msg)
Print each pass/phase message by converting a string into blue string output.
Definition SVFUtil.cpp:101
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition SVFUtil.cpp:78
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
constexpr std::remove_reference< T >::type && move(T &&t) noexcept
Definition SVFUtil.h:420
std::string extractClsNameFromDynCast(const CallBase *callBase)
extract class name from cpp dyncast function
Definition CppUtil.cpp:993
bool classTyHasVTable(const StructType *ty)
Definition CppUtil.cpp:644
bool isClsNameSource(const Value *val)
Definition CppUtil.cpp:935
Set< std::string > extractClsNamesFromFunc(const Function *foo)
extract class name from the c++ function name, e.g., constructor/destructors
Definition CppUtil.cpp:781
bool isDynCast(const Function *foo)
whether foo is a cpp dyncast function
Definition CppUtil.cpp:983
for isBitcode
Definition BasicTypes.h:70
llvm::Type Type
Definition BasicTypes.h:87
llvm::CallBase CallBase
Definition BasicTypes.h:153
llvm::BasicBlock BasicBlock
Definition BasicTypes.h:90
llvm::AllocaInst AllocaInst
Definition BasicTypes.h:157
llvm::Function Function
Definition BasicTypes.h:89
llvm::GlobalValue GlobalValue
Definition BasicTypes.h:92
llvm::Value Value
LLVM Basic classes.
Definition BasicTypes.h:86
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
llvm::PointerType PointerType
Definition BasicTypes.h:100
llvm::StoreInst StoreInst
Definition BasicTypes.h:155
unsigned u32_t
Definition GeneralType.h:47
llvm::LLVMContext LLVMContext
Definition BasicTypes.h:72