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 535 of file ObjTypeInference.cpp.

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 }
650 if (srcs.empty())
651 {
652 WARN_MSG("Cannot find allocation: " + dumpValueAndDbgInfo(var));
653 }
654 return srcs;
655}
unsigned u32_t
Definition CommandLine.h:18
#define ABORT_IFNOT(condition, msg)
#define WARN_MSG(msg)
static LLVMModuleSet * getLLVMModuleSet()
Definition LLVMModule.h:131
ValueToSources _valueToAllocs
bool isAlloc(const SVF::Value *val)
is allocation (stack, static, heap)
std::string dumpValueAndDbgInfo(const Value *val)
Definition LLVMUtil.cpp:627
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 828 of file ObjTypeInference.cpp.

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
961}
ValueToSources _valueToAllocOrClsNameSources
bool isClsNameSource(const Value *val)
Definition CppUtil.cpp:935

◆ defaultType()

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

default type

Definition at line 114 of file ObjTypeInference.cpp.

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}
const IntegerType * int8Type()
int8 type
const Type * ptrType()
pointer type
bool isHeapAllocExtCallViaRet(const Instruction *inst)
Definition LLVMUtil.cpp:638

◆ fwFindClsNameSources()

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

forward find class name sources starting from an allocation

Definition at line 963 of file ObjTypeInference.cpp.

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}
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 206 of file ObjTypeInference.cpp.

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 :
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}
const Type * infersiteToType(const Value *val)
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 705 of file ObjTypeInference.cpp.

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}

◆ getLLVMCtx()

LLVMContext & ObjTypeInference::getLLVMCtx ( )

Definition at line 125 of file ObjTypeInference.cpp.

126{
128}
LLVMContext & getContext() const
Definition LLVMModule.h:381

◆ 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 136 of file ObjTypeInference.cpp.

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}
#define ABORT_MSG(msg)
const Type * inferPointsToType(const Value *var)
bool isMemcpyExtFun(const Function *fun)
Definition LLVMUtil.cpp:389

◆ inferPointsToType()

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

Definition at line 180 of file ObjTypeInference.cpp.

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}
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 755 of file ObjTypeInference.cpp.

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}
#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 657 of file ObjTypeInference.cpp.

658{
659 return LLVMUtil::isObject(val);
660}
bool isObject(const Value *ref)
Return true if this value refers to a object.
Definition LLVMUtil.cpp:60

◆ 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 730 of file ObjTypeInference.cpp.

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}
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition Options.h:35
u32_t getNumOfElements(const Type *ety)
Return size of this object based on LLVM value.
Definition LLVMUtil.cpp:296
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 714 of file ObjTypeInference.cpp.

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}
u32_t objTyToNumFields(const Type *objTy)

◆ typeSizeDiffTest()

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

Definition at line 691 of file ObjTypeInference.cpp.

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}
std::string dumpType(const Type *type)
Definition LLVMUtil.cpp:616
static Type * getPtrElementType(const PointerType *pty)
Definition LLVMUtil.h:132

◆ 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 666 of file ObjTypeInference.cpp.

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}
const std::string TYPEMALLOC
std::pair< s64_t, u64_t > getIntegerValue(const ConstantInt *intValue)
Definition LLVMUtil.h:83
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

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: