Static Value-Flow Analysis
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Protected Member Functions | Private Member Functions | Private Attributes | List of all members
SVF::ObjTypeInference Class Reference

#include <ObjTypeInference.h>

Public Types

typedef Set< const Value * > ValueSet
 
typedef Map< const Value *, ValueSetValueToValueSet
 
typedef ValueToValueSet ValueToInferSites
 
typedef ValueToValueSet ValueToSources
 
typedef Map< const Value *, const Type * > ValueToType
 
typedef std::pair< const Value *, boolValueBoolPair
 
typedef Map< const Value *, Set< std::string > > ValueToClassNames
 
typedef Map< const Value *, Set< const CallBase * > > ObjToClsNameSources
 

Public Member Functions

 ObjTypeInference ()=default
 
 ~ObjTypeInference ()=default
 
const TypeinferObjType (const Value *var)
 get or infer the type of the object pointed by the value
 
const TypeinferPointsToType (const Value *var)
 
void validateTypeCheck (const CallBase *cs)
 validate type inference
 
void typeSizeDiffTest (const PointerType *oPTy, const Type *iTy, const Value *val)
 
const TypedefaultType (const Value *val)
 default type
 
const TypeptrType ()
 pointer type
 
const IntegerTypeint8Type ()
 int8 type
 
LLVMContextgetLLVMCtx ()
 
const TypeselectLargestSizedType (Set< const Type * > &objTys)
 select the largest (conservative) type from all types
 
u32_t objTyToNumFields (const Type *objTy)
 
u32_t getArgPosInCall (const CallBase *callBase, const Value *arg)
 
Set< std::string > & inferThisPtrClsName (const Value *thisPtr)
 get or infer the class names of thisptr
 

Protected Member Functions

Set< const Value * > & bwFindAllocOrClsNameSources (const Value *startValue)
 
Set< const CallBase * > & fwFindClsNameSources (const Value *startValue)
 forward find class name sources starting from an allocation
 

Private Member Functions

const TypefwInferObjType (const Value *var)
 forward infer the type of the object pointed by var
 
Set< const Value * > & bwfindAllocOfVar (const Value *var)
 backward collect all possible allocation sites (stack, static, heap) of var
 
bool isAlloc (const SVF::Value *val)
 is allocation (stack, static, heap)
 

Private Attributes

ValueToInferSites _valueToInferSites
 
ValueToType _valueToType
 
ValueToSources _valueToAllocs
 
ValueToClassNames _thisPtrClassNames
 
ValueToSources _valueToAllocOrClsNameSources
 
ObjToClsNameSources _objToClsNameSources
 

Detailed Description

Definition at line 39 of file ObjTypeInference.h.

Member Typedef Documentation

◆ ObjToClsNameSources

Definition at line 50 of file ObjTypeInference.h.

◆ ValueBoolPair

Definition at line 48 of file ObjTypeInference.h.

◆ ValueSet

Definition at line 43 of file ObjTypeInference.h.

◆ ValueToClassNames

Definition at line 49 of file ObjTypeInference.h.

◆ ValueToInferSites

Definition at line 45 of file ObjTypeInference.h.

◆ ValueToSources

Definition at line 46 of file ObjTypeInference.h.

◆ ValueToType

Definition at line 47 of file ObjTypeInference.h.

◆ ValueToValueSet

Definition at line 44 of file ObjTypeInference.h.

Constructor & Destructor Documentation

◆ ObjTypeInference()

SVF::ObjTypeInference::ObjTypeInference ( )
explicitdefault

◆ ~ObjTypeInference()

SVF::ObjTypeInference::~ObjTypeInference ( )
default

Member Function Documentation

◆ bwfindAllocOfVar()

Set< const Value * > & ObjTypeInference::bwfindAllocOfVar ( const Value var)
private

backward collect all possible allocation sites (stack, static, heap) of var

backward collect all possible allocation sites (stack, static, heap) of var

Parameters
var
Returns

Definition at line 557 of file ObjTypeInference.cpp.

558{
559
560 // consult cache
561 auto tIt = _valueToAllocs.find(var);
562 if (tIt != _valueToAllocs.end())
563 {
564 return tIt->second;
565 }
566
567 // simulate the call stack, the second element indicates whether we should update sources for current value
569 Set<ValueBoolPair> visited;
570 workList.push({var, false});
571 while (!workList.empty())
572 {
573 auto curPair = workList.pop();
574 if (visited.count(curPair)) continue;
575 visited.insert(curPair);
576 const Value *curValue = curPair.first;
577 bool canUpdate = curPair.second;
578
579 Set<const Value *> sources;
580 auto insertAllocs = [&sources, &canUpdate](const Value *source)
581 {
582 if (canUpdate) sources.insert(source);
583 };
584 auto insertAllocsOrPushWorklist = [this, &sources, &workList, &canUpdate](const auto &pUser)
585 {
586 auto vIt = _valueToAllocs.find(pUser);
587 if (canUpdate)
588 {
589 if (vIt != _valueToAllocs.end())
590 {
591 sources.insert(vIt->second.begin(), vIt->second.end());
592 }
593 }
594 else
595 {
596 if (vIt == _valueToAllocs.end()) workList.push({pUser, false});
597 }
598 };
599
600 if (!canUpdate && !_valueToAllocs.count(curValue))
601 {
602 workList.push({curValue, true});
603 }
604
605 if (isAlloc(curValue))
606 {
608 }
609 else if (const auto *bitCastInst = SVFUtil::dyn_cast<BitCastInst>(curValue))
610 {
611 Value *prevVal = bitCastInst->getOperand(0);
613 }
614 else if (const auto *phiNode = SVFUtil::dyn_cast<PHINode>(curValue))
615 {
616 for (u32_t i = 0; i < phiNode->getNumOperands(); ++i)
617 {
619 }
620 }
621 else if (const auto *loadInst = SVFUtil::dyn_cast<LoadInst>(curValue))
622 {
623 for (const auto use: loadInst->getPointerOperand()->users())
624 {
625 if (const StoreInst *storeInst = SVFUtil::dyn_cast<StoreInst>(use))
626 {
627 if (storeInst->getPointerOperand() == loadInst->getPointerOperand())
628 {
629 insertAllocsOrPushWorklist(storeInst->getValueOperand());
630 }
631 }
632 }
633 }
634 else if (const auto *argument = SVFUtil::dyn_cast<Argument>(curValue))
635 {
636 for (const auto use: argument->getParent()->users())
637 {
638 if (const CallBase *callBase = SVFUtil::dyn_cast<CallBase>(use))
639 {
640 // skip function as parameter
641 // e.g., call void @foo(%struct.ssl_ctx_st* %9, i32 (i8*, i32, i32, i8*)* @passwd_callback)
642 if (callBase->getCalledFunction() != argument->getParent()) continue;
643 u32_t pos = argument->getParent()->isVarArg() ? 0 : argument->getArgNo();
644 insertAllocsOrPushWorklist(callBase->getArgOperand(pos));
645 }
646 }
647 }
648 else if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(curValue))
649 {
650 ABORT_IFNOT(!callBase->doesNotReturn(), "callbase does not return:" + dumpValueAndDbgInfo(callBase));
651 if (Function *callee = callBase->getCalledFunction())
652 {
653 if (!callee->isDeclaration())
654 {
655
657 const BasicBlock* exitBB = llvmmodule->getFunExitBB(callee);
658 assert (exitBB && "exit bb is not a basic block?");
659 const Value *pValue = &exitBB->back();
660 const auto *retInst = SVFUtil::dyn_cast<ReturnInst>(pValue);
661 ABORT_IFNOT(retInst && retInst->getReturnValue(), "not return inst?");
662 insertAllocsOrPushWorklist(retInst->getReturnValue());
663 }
664 }
665 }
666 if (canUpdate)
667 {
669 }
670 }
672 if (srcs.empty())
673 {
674 WARN_MSG("Cannot find allocation: " + dumpValueAndDbgInfo(var));
675 }
676 return srcs;
677}
unsigned u32_t
Definition CommandLine.h:18
#define ABORT_IFNOT(condition, msg)
#define WARN_MSG(msg)
static LLVMModuleSet * getLLVMModuleSet()
Definition LLVMModule.h:133
ValueToSources _valueToAllocs
bool isAlloc(const SVF::Value *val)
is allocation (stack, static, heap)
std::string dumpValueAndDbgInfo(const Value *val)
Definition LLVMUtil.cpp:628
constexpr std::remove_reference< T >::type && move(T &&t) noexcept
Definition SVFUtil.h:420
llvm::CallBase CallBase
Definition BasicTypes.h:153
llvm::BasicBlock BasicBlock
Definition BasicTypes.h:90
llvm::Function Function
Definition BasicTypes.h:89
llvm::Value Value
LLVM Basic classes.
Definition BasicTypes.h:86
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
llvm::StoreInst StoreInst
Definition BasicTypes.h:155

◆ bwFindAllocOrClsNameSources()

Set< const Value * > & ObjTypeInference::bwFindAllocOrClsNameSources ( const Value startValue)
protected

find all possible allocations or class name sources (e.g., constructors/destructors or template functions) starting from a value

find all possible allocations or class name sources (e.g., constructors/destructors or template functions) if we already find class name sources, we don't need to find the allocations and forward find class name sources

Parameters
startValue
Returns

Definition at line 850 of file ObjTypeInference.cpp.

851{
852
853 // consult cache
856 {
857 return tIt->second;
858 }
859
860 // simulate the call stack, the second element indicates whether we should update sources for current value
862 Set<ValueBoolPair> visited;
863 workList.push({startValue, false});
864 while (!workList.empty())
865 {
866 auto curPair = workList.pop();
867 if (visited.count(curPair)) continue;
868 visited.insert(curPair);
869 const Value *curValue = curPair.first;
870 bool canUpdate = curPair.second;
871
872 Set<const Value *> sources;
873 auto insertSource = [&sources, &canUpdate](const Value *source)
874 {
875 if (canUpdate) sources.insert(source);
876 };
877 auto insertSourcesOrPushWorklist = [this, &sources, &workList, &canUpdate](const auto &pUser)
878 {
880 if (canUpdate)
881 {
882 if (vIt != _valueToAllocOrClsNameSources.end() && !vIt->second.empty())
883 {
884 sources.insert(vIt->second.begin(), vIt->second.end());
885 }
886 }
887 else
888 {
889 if (vIt == _valueToAllocOrClsNameSources.end()) workList.push({pUser, false});
890 }
891 };
892
894 {
895 workList.push({curValue, true});
896 }
897
898 // If current value is an instruction inside a constructor/destructor/template, use it as a source
899 if (const auto *inst = SVFUtil::dyn_cast<Instruction>(curValue))
900 {
901 if (const auto *parent = inst->getFunction())
902 {
904 }
905 }
906
907 // If the current value is an object (global, heap, stack, etc) or name source (constructor/destructor,
908 // a C++ dynamic cast, or a template function), use it as a source
910 {
912 }
913
914 // Explore the current value further depending on the type of the value; use cached values if possible
915 if (const auto *getElementPtrInst = SVFUtil::dyn_cast<GetElementPtrInst>(curValue))
916 {
918 }
919 else if (const auto *bitCastInst = SVFUtil::dyn_cast<BitCastInst>(curValue))
920 {
922 }
923 else if (const auto *phiNode = SVFUtil::dyn_cast<PHINode>(curValue))
924 {
925 for (const auto *op : phiNode->operand_values())
926 {
928 }
929 }
930 else if (const auto *loadInst = SVFUtil::dyn_cast<LoadInst>(curValue))
931 {
932 for (const auto *user : loadInst->getPointerOperand()->users())
933 {
934 if (const auto *storeInst = SVFUtil::dyn_cast<StoreInst>(user))
935 {
936 if (storeInst->getPointerOperand() == loadInst->getPointerOperand())
937 {
938 insertSourcesOrPushWorklist(storeInst->getValueOperand());
939 }
940 }
941 }
942 }
943 else if (const auto *argument = SVFUtil::dyn_cast<Argument>(curValue))
944 {
945 for (const auto *user: argument->getParent()->users())
946 {
947 if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(user))
948 {
949 // skip function as parameter
950 // e.g., call void @foo(%struct.ssl_ctx_st* %9, i32 (i8*, i32, i32, i8*)* @passwd_callback)
951 if (callBase->getCalledFunction() != argument->getParent()) continue;
952 u32_t pos = argument->getParent()->isVarArg() ? 0 : argument->getArgNo();
954 }
955 }
956 }
957 else if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(curValue))
958 {
959 ABORT_IFNOT(!callBase->doesNotReturn(), "callbase does not return:" + dumpValueAndDbgInfo(callBase));
960 if (const auto *callee = callBase->getCalledFunction())
961 {
962 if (!callee->isDeclaration())
963 {
965 const BasicBlock* exitBB = llvmmodule->getFunExitBB(callee);
966 assert (exitBB && "exit bb is not a basic block?");
967 const Value *pValue = &exitBB->back();
968 const auto *retInst = SVFUtil::dyn_cast<ReturnInst>(pValue);
969 ABORT_IFNOT(retInst && retInst->getReturnValue(), "not return inst?");
970 insertSourcesOrPushWorklist(retInst->getReturnValue());
971 }
972 }
973 }
974
975 // If updating is allowed; store the gathered sources as sources for the current value in the cache
976 if (canUpdate)
977 {
979 }
980 }
981
983}
ValueToSources _valueToAllocOrClsNameSources
bool isClsNameSource(const Value *val)
Definition CppUtil.cpp:935

◆ defaultType()

const Type * ObjTypeInference::defaultType ( const Value val)

default type

Definition at line 132 of file ObjTypeInference.cpp.

133{
134 ABORT_IFNOT(val, "val cannot be null");
135 // heap has a default type of 8-bit integer type
136 if (SVFUtil::isa<Instruction>(val) && LLVMUtil::isHeapAllocExtCallViaRet(
137 SVFUtil::cast<Instruction>(val)))
138 return int8Type();
139 // otherwise we return a pointer type in the default address space
140 return ptrType();
141}
const IntegerType * int8Type()
int8 type
const Type * ptrType()
pointer type
bool isHeapAllocExtCallViaRet(const Instruction *inst)
Definition LLVMUtil.cpp:639

◆ fwFindClsNameSources()

Set< const CallBase * > & ObjTypeInference::fwFindClsNameSources ( const Value startValue)
protected

forward find class name sources starting from an allocation

Definition at line 985 of file ObjTypeInference.cpp.

986{
987 assert(startValue && "startValue was null?");
988
989 // consult cache
991 if (tIt != _objToClsNameSources.end())
992 {
993 return tIt->second;
994 }
995
996 Set<const CallBase *> sources;
997
998 // Lambda for adding a callee to the sources iff it is a constructor/destructor/template/dyncast
999 auto inferViaCppCall = [&sources](const CallBase *caller)
1000 {
1001 if (!caller) return;
1002 if (isClsNameSource(caller)) sources.insert(caller);
1003 };
1004
1005 // Find all calls of starting val (or through cast); add as potential source iff applicable
1006 for (const auto *user : startValue->users())
1007 {
1008 if (const auto *caller = SVFUtil::dyn_cast<CallBase>(user))
1009 {
1011 }
1012 else if (const auto *bitcast = SVFUtil::dyn_cast<BitCastInst>(user))
1013 {
1014 for (const auto *cast_user : bitcast->users())
1015 {
1016 if (const auto *caller = SVFUtil::dyn_cast<CallBase>(cast_user))
1017 {
1019 }
1020 }
1021 }
1022 }
1023
1024 // Store sources in cache for starting value & return the found sources
1026}
ObjToClsNameSources _objToClsNameSources

◆ fwInferObjType()

const Type * ObjTypeInference::fwInferObjType ( const Value var)
private

forward infer the type of the object pointed by var

forward infer the type of the object pointed by var

Parameters
var

Definition at line 226 of file ObjTypeInference.cpp.

227{
228 if (const AllocaInst *allocaInst = SVFUtil::dyn_cast<AllocaInst>(var))
229 {
230 // stack object
232 }
233 else if (const GlobalValue *global = SVFUtil::dyn_cast<GlobalValue>(var))
234 {
235 // global object
236 return infersiteToType(global);
237 }
238 else
239 {
240 // for heap or static object, we forward infer its type
241
242 // consult cache
243 auto tIt = _valueToType.find(var);
244 if (tIt != _valueToType.end())
245 {
246 return tIt->second ? tIt->second : defaultType(var);
247 }
248
249 // simulate the call stack, the second element indicates whether we should update valueTypes for current value
251 Set<ValueBoolPair> visited;
252 workList.push({var, false});
253
254 while (!workList.empty())
255 {
256 auto curPair = workList.pop();
257 if (visited.count(curPair))
258 continue;
259 visited.insert(curPair);
260 const Value* curValue = curPair.first;
261 bool canUpdate = curPair.second;
263
265 &canUpdate](const Value* infersite)
266 {
267 if (canUpdate)
268 infersites.insert(infersite);
269 };
271 [this, &infersites, &workList, &canUpdate](const auto& pUser)
272 {
273 auto vIt = _valueToInferSites.find(pUser);
274 if (canUpdate)
275 {
276 if (vIt != _valueToInferSites.end())
277 {
278 infersites.insert(vIt->second.begin(),
279 vIt->second.end());
280 }
281 }
282 else
283 {
284 if (vIt == _valueToInferSites.end())
285 workList.push({pUser, false});
286 }
287 };
288 if (!canUpdate && !_valueToInferSites.count(curValue))
289 {
290 workList.push({curValue, true});
291 }
292 if (const auto* gepInst =
293 SVFUtil::dyn_cast<GetElementPtrInst>(curValue))
295 // hasUseList() was removed from Value's public API in LLVM 18-20; use
296 // the version-portable compat shim defined above instead.
297 if (!hasUseList(curValue)) continue;
298 for (const auto it : curValue->users())
299 {
300 if (const auto* loadInst = SVFUtil::dyn_cast<LoadInst>(it))
301 {
302 /*
303 * infer based on load, e.g.,
304 %call = call i8* malloc()
305 %1 = bitcast i8* %call to %struct.MyStruct*
306 %q = load %struct.MyStruct, %struct.MyStruct* %1
307 */
309 }
310 else if (const auto* storeInst =
311 SVFUtil::dyn_cast<StoreInst>(it))
312 {
313 if (storeInst->getPointerOperand() == curValue)
314 {
315 /*
316 * infer based on store (pointer operand), e.g.,
317 %call = call i8* malloc()
318 %1 = bitcast i8* %call to %struct.MyStruct*
319 store %struct.MyStruct .., %struct.MyStruct* %1
320 */
322 }
323 else
324 {
325 for (const auto nit :
327 {
328 /*
329 * propagate across store (value operand) and load
330 %call = call i8* malloc()
331 store i8* %call, i8** %p
332 %q = load i8*, i8** %p
333 ..infer based on %q..
334 */
335 if (SVFUtil::isa<LoadInst>(nit))
337 }
338 /*
339 * infer based on store (value operand) <- gep (result element)
340 */
341 if (const auto* gepInst =
342 SVFUtil::dyn_cast<GetElementPtrInst>(
343 storeInst->getPointerOperand()))
344 {
345 /*
346 %call1 = call i8* @TYPE_MALLOC(i32 noundef 16, i32
347 noundef 2), !dbg !39 %2 = bitcast i8* %call1 to
348 %struct.MyStruct*, !dbg !41 %3 = load
349 %struct.MyStruct*, %struct.MyStruct** %p, align 8,
350 !dbg !42 %next = getelementptr inbounds
351 %struct.MyStruct, %struct.MyStruct* %3, i32 0, i32
352 1, !dbg !43 store %struct.MyStruct* %2,
353 %struct.MyStruct** %next, align 8, !dbg !44 %5 =
354 load %struct.MyStruct*, %struct.MyStruct** %p,
355 align 8, !dbg !48 %next3 = getelementptr inbounds
356 %struct.MyStruct, %struct.MyStruct* %5, i32 0, i32
357 1, !dbg !49 %6 = load %struct.MyStruct*,
358 %struct.MyStruct** %next3, align 8, !dbg !49 infer
359 site -> %f1 = getelementptr inbounds
360 %struct.MyStruct, %struct.MyStruct* %6, i32 0, i32
361 0, !dbg !50
362 */
363 const Value* gepBase = gepInst->getPointerOperand();
364 if (const auto* load =
365 SVFUtil::dyn_cast<LoadInst>(gepBase))
366 {
367 for (const auto loadUse :
368 load->getPointerOperand()->users())
369 {
370 if (loadUse == load ||
371 !SVFUtil::isa<LoadInst>(loadUse))
372 continue;
373 for (const auto gepUse : loadUse->users())
374 {
375 if (!SVFUtil::isa<GetElementPtrInst>(
376 gepUse))
377 continue;
378 for (const auto loadUse2 :
379 gepUse->users())
380 {
381 if (SVFUtil::isa<LoadInst>(
382 loadUse2))
383 {
385 loadUse2);
386 }
387 }
388 }
389 }
390 }
391 else if (const auto* alloc =
392 SVFUtil::dyn_cast<AllocaInst>(gepBase))
393 {
394 /*
395 %2 = alloca %struct.ll, align 8
396 store i32 0, ptr %1, align 4
397 %3 = call noalias noundef nonnull ptr
398 @_Znwm(i64 noundef 16) #2 %4 = getelementptr
399 inbounds %struct.ll, ptr %2, i32 0, i32 1
400 store ptr %3, ptr %4, align 8
401 %5 = getelementptr inbounds %struct.ll, ptr
402 %2, i32 0, i32 1 %6 = load ptr, ptr %5, align
403 8 %7 = getelementptr inbounds %struct.ll, ptr
404 %6, i32 0, i32 0
405 */
406 for (const auto gepUse : alloc->users())
407 {
408 if (!SVFUtil::isa<GetElementPtrInst>(
409 gepUse))
410 continue;
411 for (const auto loadUse2 : gepUse->users())
412 {
413 if (SVFUtil::isa<LoadInst>(loadUse2))
414 {
416 loadUse2);
417 }
418 }
419 }
420 }
421 }
422 }
423 }
424 else if (const auto* gepInst =
425 SVFUtil::dyn_cast<GetElementPtrInst>(it))
426 {
427 /*
428 * infer based on gep (pointer operand)
429 %call = call i8* malloc()
430 %1 = bitcast i8* %call to %struct.MyStruct*
431 %next = getelementptr inbounds %struct.MyStruct,
432 %struct.MyStruct* %1, i32 0..
433 */
434 if (gepInst->getPointerOperand() == curValue)
436 }
437 else if (const auto* bitcast =
438 SVFUtil::dyn_cast<BitCastInst>(it))
439 {
440 // continue on bitcast
442 }
443 else if (const auto* phiNode = SVFUtil::dyn_cast<PHINode>(it))
444 {
445 // continue on bitcast
447 }
448 else if (const auto* retInst =
449 SVFUtil::dyn_cast<ReturnInst>(it))
450 {
451 /*
452 * propagate from return to caller
453 Function Attrs: noinline nounwind optnone uwtable
454 define dso_local i8* @malloc_wrapper() #0 !dbg !22 {
455 entry:
456 %call = call i8* @malloc(i32 noundef 16), !dbg !25
457 ret i8* %call, !dbg !26
458 }
459 %call = call i8* @malloc_wrapper()
460 ..infer based on %call..
461 */
462 for (const auto callsite : retInst->getFunction()->users())
463 {
464 if (const auto* callBase =
465 SVFUtil::dyn_cast<CallBase>(callsite))
466 {
467 // skip function as parameter
468 // e.g., call void @foo(%struct.ssl_ctx_st* %9, i32 (i8*, i32, i32, i8*)* @passwd_callback)
469 if (callBase->getCalledFunction() !=
470 retInst->getFunction())
471 continue;
473 }
474 }
475 }
476 else if (const auto* callBase = SVFUtil::dyn_cast<CallBase>(it))
477 {
478 /*
479 * propagate from callsite to callee
480 %call = call i8* @malloc(i32 noundef 16)
481 %0 = bitcast i8* %call to %struct.Node*, !dbg !43
482 call void @foo(%struct.Node* noundef %0), !dbg !45
483
484 define dso_local void @foo(%struct.Node* noundef %param)
485 #0 !dbg !22 {...}
486 ..infer based on the formal param %param..
487 */
488 // skip global function value -> callsite
489 // e.g., def @foo() -> call @foo()
490 // we don't skip function as parameter, e.g., def @foo() -> call @bar(..., @foo)
491 if (SVFUtil::isa<Function>(curValue) &&
492 curValue == callBase->getCalledFunction())
493 continue;
494 // skip indirect call
495 // e.g., %0 = ... -> call %0(...)
496 if (!callBase->hasArgument(curValue))
497 continue;
498 if (Function* calleeFunc = callBase->getCalledFunction())
499 {
501 // 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: .......
502 // 6: }
503 // 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''
504 if (calleeFunc->isVarArg())
505 {
506 // conservatively track all var args
507 for (auto& I : instructions(calleeFunc))
508 {
509 if (auto* load =
510 llvm::dyn_cast<llvm::LoadInst>(&I))
511 {
512 llvm::Value* loadPointer =
513 load->getPointerOperand();
514 if (loadPointer->getName().compare(
515 "vaarg.addr") == 0)
516 {
518 }
519 }
520 }
521 }
522 else if (!calleeFunc->isDeclaration())
523 {
525 calleeFunc->getArg(pos));
526 }
527 }
528 }
529 }
530 if (canUpdate)
531 {
533 std::transform(infersites.begin(), infersites.end(),
534 std::inserter(types, types.begin()),
538 }
539 }
540 const Type* type = _valueToType[var];
541 if (type == nullptr)
542 {
544 WARN_MSG("Using default type, trace ID is " +
545 std::to_string(traceId) + ":" + dumpValueAndDbgInfo(var));
546 }
547 ABORT_IFNOT(type, "type cannot be a null ptr");
548 return type;
549 }
550}
const Type * infersiteToType(const Value *val)
static bool hasUseList(const Value *v)
newitem type
Definition cJSON.cpp:2739
ValueToInferSites _valueToInferSites
const Type * selectLargestSizedType(Set< const Type * > &objTys)
select the largest (conservative) type from all types
u32_t getArgPosInCall(const CallBase *callBase, const Value *arg)
const Type * defaultType(const Value *val)
default type
llvm::Type Type
Definition BasicTypes.h:87
llvm::AllocaInst AllocaInst
Definition BasicTypes.h:157
llvm::GlobalValue GlobalValue
Definition BasicTypes.h:92

◆ getArgPosInCall()

u32_t ObjTypeInference::getArgPosInCall ( const CallBase callBase,
const Value arg 
)

Definition at line 727 of file ObjTypeInference.cpp.

728{
729 assert(callBase->hasArgument(arg) && "callInst does not have argument arg?");
730 auto it = std::find(callBase->arg_begin(), callBase->arg_end(), arg);
731 assert(it != callBase->arg_end() && "Didn't find argument?");
732 return std::distance(callBase->arg_begin(), it);
733}

◆ getLLVMCtx()

LLVMContext & ObjTypeInference::getLLVMCtx ( )

Definition at line 143 of file ObjTypeInference.cpp.

144{
146}
LLVMContext & getContext() const
Definition LLVMModule.h:384

◆ inferObjType()

const Type * ObjTypeInference::inferObjType ( const Value var)

get or infer the type of the object pointed by the value

get or infer the type of the object pointed by var if the start value is a source (alloc/global, heap, static), call fwInferObjType if not, find allocations and then forward get or infer types

Parameters
val

Definition at line 154 of file ObjTypeInference.cpp.

155{
156 const Type* res = inferPointsToType(var);
157 // infer type by leveraging the type alignment of src and dst in memcpy
158 // for example,
159 //
160 // %tmp = alloca %struct.outer
161 // %inner_v = alloca %struct.inner
162 // %ptr = getelementptr inbounds %struct.outer, ptr %tmp, i32 0, i32 1, !dbg !38
163 // %0 = load ptr, ptr %ptr, align 8, !dbg !38
164 // call void @llvm.memcpy.p0.p0.i64(ptr %inner_v, ptr %0, i64 24, i1 false)
165 //
166 // It is difficult to infer the type of %0 without deep alias analysis,
167 // but we can infer the obj type of %0 based on that of %inner_v.
168 if (res == defaultType(var))
169 {
170 // hasUseList() was removed from Value's public API in LLVM 18-20; use
171 // the version-portable compat shim defined above instead.
172 if (!hasUseList(var)) return res;
173 for (const auto& use: var->users())
174 {
175 if (const CallBase* cs = SVFUtil::dyn_cast<CallBase>(use))
176 {
177 if (const Function* calledFun = cs->getCalledFunction())
179 {
180 assert(cs->getNumOperands() > 1 && "arguments should be greater than 1");
181 const Value* dst = cs->getArgOperand(0);
182 const Value* src = cs->getArgOperand(1);
183 if(calledFun->getName().find("iconv") != std::string::npos)
184 {
185 if(var == cs->getArgOperand(0))
186 return res;
187 dst = cs->getArgOperand(3), src = cs->getArgOperand(1);
188 }
189
190 if (var == dst) return inferPointsToType(src);
191 else if (var == src) return inferPointsToType(dst);
192 else ABORT_MSG("invalid memcpy call");
193 }
194 }
195 }
196 }
197 return res;
198}
#define ABORT_MSG(msg)
const Type * inferPointsToType(const Value *var)
bool isMemcpyExtFun(const Function *fun)
Definition LLVMUtil.cpp:390

◆ inferPointsToType()

const Type * ObjTypeInference::inferPointsToType ( const Value var)

Definition at line 200 of file ObjTypeInference.cpp.

201{
202 if (isAlloc(var)) return fwInferObjType(var);
205 if (sources.empty())
206 {
207 // cannot find allocation, try to fw infer starting from var
208 types.insert(fwInferObjType(var));
209 }
210 else
211 {
212 for (const auto &source: sources)
213 {
214 types.insert(fwInferObjType(source));
215 }
216 }
218 ABORT_IFNOT(largestTy, "return type cannot be null");
219 return largestTy;
220}
Set< const Value * > & bwfindAllocOfVar(const Value *var)
backward collect all possible allocation sites (stack, static, heap) of var
const Type * fwInferObjType(const Value *var)
forward infer the type of the object pointed by var

◆ inferThisPtrClsName()

Set< std::string > & ObjTypeInference::inferThisPtrClsName ( const Value thisPtr)

get or infer the class names of thisptr

get or infer the class names of thisptr; starting from :param:thisPtr, will walk backwards to find all potential sources for the class name. Valid sources include global or stack variables, heap allocations, or C++ dynamic casts/constructors/destructors. If the source site is a global/stack/heap variable, find the corresponding constructor/destructor to extract the class' name from (since the type of the variable is not reliable but the demangled name is)

Parameters
thisPtr
Returns
a set of all possible type names that :param:thisPtr could point to

Definition at line 777 of file ObjTypeInference.cpp.

778{
779 auto it = _thisPtrClassNames.find(thisPtr);
780 if (it != _thisPtrClassNames.end()) return it->second;
781
783
784 // Lambda for checking a function is a valid name source & extracting a class name from it
785 auto addNamesFromFunc = [&names](const Function *func) -> void
786 {
787 ABORT_IFNOT(isClsNameSource(func), "Func is invalid class name source: " + dumpValueAndDbgInfo(func));
788 for (const auto &name : extractClsNamesFromFunc(func)) names.insert(name);
789 };
790
791 // Lambda for getting callee & extracting class name for calls to constructors/destructors/template funcs
792 auto addNamesFromCall = [&names, &addNamesFromFunc](const CallBase *call) -> void
793 {
794 ABORT_IFNOT(isClsNameSource(call), "Call is invalid class name source: " + dumpValueAndDbgInfo(call));
795
796 const auto *func = call->getCalledFunction();
797 if (isDynCast(func)) names.insert(extractClsNameFromDynCast(call));
799 };
800
801 // Walk backwards to find all valid source sites for the pointer (e.g. stack/global/heap variables)
802 for (const auto &val: bwFindAllocOrClsNameSources(thisPtr))
803 {
804 // A source site is either a constructor/destructor/template function from which the class name can be
805 // extracted; a call to a C++ constructor/destructor/template function from which the class name can be
806 // extracted; or an allocation site of an object (i.e. a stack/global/heap variable), from which a
807 // forward walk can be performed to find calls to C++ constructor/destructor/template functions from
808 // which the class' name can then be extracted; skip starting pointer
809 if (val == thisPtr) continue;
810
811 if (const auto *func = SVFUtil::dyn_cast<Function>(val))
812 {
813 // Constructor/destructor/template func; extract name from func directly
815 }
816 else if (isClsNameSource(val))
817 {
818 // Call to constructor/destructor/template func; get callee; extract name from callee
819 ABORT_IFNOT(SVFUtil::isa<CallBase>(val), "Call source site is not a callbase: " + dumpValueAndDbgInfo(val));
820 addNamesFromCall(SVFUtil::cast<CallBase>(val));
821 }
822 else if (isAlloc(val))
823 {
824 // Stack/global/heap allocation site; walk forward; find constructor/destructor/template calls
825 ABORT_IFNOT((SVFUtil::isa<AllocaInst, CallBase, GlobalVariable>(val)),
826 "Alloc site source is not a stack/heap/global variable: " + dumpValueAndDbgInfo(val));
827 for (const auto *src : fwFindClsNameSources(val))
828 {
829 if (const auto *func = SVFUtil::dyn_cast<Function>(src)) addNamesFromFunc(func);
830 else if (const auto *call = SVFUtil::dyn_cast<CallBase>(src)) addNamesFromCall(call);
831 else ABORT_MSG("Source site from forward walk is invalid: " + dumpValueAndDbgInfo(src));
832 }
833 }
834 else
835 {
836 ERR_MSG("Unsupported source type found:" + dumpValueAndDbgInfo(val));
837 }
838 }
839
841}
#define ERR_MSG(msg)
const char *const name
Definition cJSON.h:264
Set< const Value * > & bwFindAllocOrClsNameSources(const Value *startValue)
ValueToClassNames _thisPtrClassNames
Set< const CallBase * > & fwFindClsNameSources(const Value *startValue)
forward find class name sources starting from an allocation
std::string extractClsNameFromDynCast(const CallBase *callBase)
extract class name from cpp dyncast function
Definition CppUtil.cpp:993
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

◆ int8Type()

const IntegerType * SVF::ObjTypeInference::int8Type ( )
inline

int8 type

Definition at line 89 of file ObjTypeInference.h.

90 {
91 return Type::getInt8Ty(getLLVMCtx());
92 }

◆ isAlloc()

bool ObjTypeInference::isAlloc ( const SVF::Value val)
private

is allocation (stack, static, heap)

Definition at line 679 of file ObjTypeInference.cpp.

680{
681 return LLVMUtil::isObject(val);
682}
bool isObject(const Value *ref)
Return true if this value refers to a object.
Definition LLVMUtil.cpp:61

◆ objTyToNumFields()

u32_t ObjTypeInference::objTyToNumFields ( const Type objTy)

For an C++ class, it can have variant elements depending on the vtable size, Hence we only handle non-cpp-class object, the type of the cpp class is treated as default PointerType

Definition at line 752 of file ObjTypeInference.cpp.

753{
755 if (SVFUtil::isa<ArrayType>(objTy))
757 else if (const auto *st = SVFUtil::dyn_cast<StructType>(objTy))
758 {
761 if (!classTyHasVTable(st))
763 }
764 return num;
765}
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition Options.h:34
u32_t getNumOfElements(const Type *ety)
Return size of this object based on LLVM value.
Definition LLVMUtil.cpp:297
bool classTyHasVTable(const StructType *ty)
Definition CppUtil.cpp:644

◆ ptrType()

const Type * SVF::ObjTypeInference::ptrType ( )
inline

pointer type

Definition at line 83 of file ObjTypeInference.h.

84 {
85 return PointerType::getUnqual(getLLVMCtx());
86 }

◆ selectLargestSizedType()

const Type * ObjTypeInference::selectLargestSizedType ( Set< const Type * > &  objTys)

select the largest (conservative) type from all types

Definition at line 736 of file ObjTypeInference.cpp.

737{
738 if (objTys.empty()) return nullptr;
739 // map type size to types from with key in descending order
741 for (const Type *ty: objTys)
742 {
744 }
745 assert(!typeSzToTypes.empty() && "typeSzToTypes cannot be empty");
747 std::tie(std::ignore, largestTypes) = *typeSzToTypes.begin();
748 assert(!largestTypes.empty() && "largest element cannot be empty");
749 return *largestTypes.begin();
750}
u32_t objTyToNumFields(const Type *objTy)

◆ typeSizeDiffTest()

void ObjTypeInference::typeSizeDiffTest ( const PointerType oPTy,
const Type iTy,
const Value val 
)

Definition at line 713 of file ObjTypeInference.cpp.

714{
715#if TYPE_DEBUG
719 {
720 ERR_MSG("original type is:" + dumpType(oTy));
721 ERR_MSG("infered type is:" + dumpType(iTy));
722 ABORT_MSG("wrong type, trace ID is " + std::to_string(traceId) + ":" + dumpValueAndDbgInfo(val));
723 }
724#endif
725}
std::string dumpType(const Type *type)
Definition LLVMUtil.cpp:617
static Type * getPtrElementType(const PointerType *pty)
Definition LLVMUtil.h:134

◆ validateTypeCheck()

void ObjTypeInference::validateTypeCheck ( const CallBase cs)

validate type inference

validate type inference

Parameters
cs: stub malloc function with element number label

Definition at line 688 of file ObjTypeInference.cpp.

689{
690 if (const Function *func = cs->getCalledFunction())
691 {
692 if (func->getName().find(TYPEMALLOC) != std::string::npos)
693 {
694 const Type *objType = fwInferObjType(cs);
695 const auto *pInt =
696 SVFUtil::dyn_cast<llvm::ConstantInt>(cs->getOperand(1));
697 assert(pInt && "the second argument is a integer");
700 SVFUtil::outs() << SVFUtil::sucMsg("\t SUCCESS :") << dumpValueAndDbgInfo(cs)
701 << SVFUtil::pasMsg(" TYPE: ")
702 << dumpType(objType) << "\n";
703 else
704 {
705 SVFUtil::errs() << SVFUtil::errMsg("\t FAILURE :") << ":" << dumpValueAndDbgInfo(cs) << " TYPE: "
706 << dumpType(objType) << "\n";
707 abort();
708 }
709 }
710 }
711}
const std::string TYPEMALLOC
std::pair< s64_t, u64_t > getIntegerValue(const ConstantInt *intValue)
Definition LLVMUtil.h:85
std::string sucMsg(const std::string &msg)
Returns successful message by converting a string into green string output.
Definition SVFUtil.cpp:59
std::string pasMsg(const std::string &msg)
Print each pass/phase message by converting a string into blue string output.
Definition SVFUtil.cpp:105
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition SVFUtil.cpp:82
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52

Member Data Documentation

◆ _objToClsNameSources

ObjToClsNameSources SVF::ObjTypeInference::_objToClsNameSources
private

Definition at line 59 of file ObjTypeInference.h.

◆ _thisPtrClassNames

ValueToClassNames SVF::ObjTypeInference::_thisPtrClassNames
private

Definition at line 57 of file ObjTypeInference.h.

◆ _valueToAllocOrClsNameSources

ValueToSources SVF::ObjTypeInference::_valueToAllocOrClsNameSources
private

Definition at line 58 of file ObjTypeInference.h.

◆ _valueToAllocs

ValueToSources SVF::ObjTypeInference::_valueToAllocs
private

Definition at line 56 of file ObjTypeInference.h.

◆ _valueToInferSites

ValueToInferSites SVF::ObjTypeInference::_valueToInferSites
private

Definition at line 54 of file ObjTypeInference.h.

◆ _valueToType

ValueToType SVF::ObjTypeInference::_valueToType
private

Definition at line 55 of file ObjTypeInference.h.


The documentation for this class was generated from the following files: