Static Value-Flow Analysis
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
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 529 of file ObjTypeInference.cpp.

530{
531
532 // consult cache
533 auto tIt = _valueToAllocs.find(var);
534 if (tIt != _valueToAllocs.end())
535 {
536 return tIt->second;
537 }
538
539 // simulate the call stack, the second element indicates whether we should update sources for current value
541 Set<ValueBoolPair> visited;
542 workList.push({var, false});
543 while (!workList.empty())
544 {
545 auto curPair = workList.pop();
546 if (visited.count(curPair)) continue;
547 visited.insert(curPair);
548 const Value *curValue = curPair.first;
549 bool canUpdate = curPair.second;
550
551 Set<const Value *> sources;
552 auto insertAllocs = [&sources, &canUpdate](const Value *source)
553 {
554 if (canUpdate) sources.insert(source);
555 };
556 auto insertAllocsOrPushWorklist = [this, &sources, &workList, &canUpdate](const auto &pUser)
557 {
558 auto vIt = _valueToAllocs.find(pUser);
559 if (canUpdate)
560 {
561 if (vIt != _valueToAllocs.end())
562 {
563 sources.insert(vIt->second.begin(), vIt->second.end());
564 }
565 }
566 else
567 {
568 if (vIt == _valueToAllocs.end()) workList.push({pUser, false});
569 }
570 };
571
572 if (!canUpdate && !_valueToAllocs.count(curValue))
573 {
574 workList.push({curValue, true});
575 }
576
577 if (isAlloc(curValue))
578 {
580 }
581 else if (const auto *bitCastInst = SVFUtil::dyn_cast<BitCastInst>(curValue))
582 {
583 Value *prevVal = bitCastInst->getOperand(0);
585 }
586 else if (const auto *phiNode = SVFUtil::dyn_cast<PHINode>(curValue))
587 {
588 for (u32_t i = 0; i < phiNode->getNumOperands(); ++i)
589 {
591 }
592 }
593 else if (const auto *loadInst = SVFUtil::dyn_cast<LoadInst>(curValue))
594 {
595 for (const auto use: loadInst->getPointerOperand()->users())
596 {
597 if (const StoreInst *storeInst = SVFUtil::dyn_cast<StoreInst>(use))
598 {
599 if (storeInst->getPointerOperand() == loadInst->getPointerOperand())
600 {
601 insertAllocsOrPushWorklist(storeInst->getValueOperand());
602 }
603 }
604 }
605 }
606 else if (const auto *argument = SVFUtil::dyn_cast<Argument>(curValue))
607 {
608 for (const auto use: argument->getParent()->users())
609 {
610 if (const CallBase *callBase = SVFUtil::dyn_cast<CallBase>(use))
611 {
612 // skip function as parameter
613 // e.g., call void @foo(%struct.ssl_ctx_st* %9, i32 (i8*, i32, i32, i8*)* @passwd_callback)
614 if (callBase->getCalledFunction() != argument->getParent()) continue;
615 u32_t pos = argument->getParent()->isVarArg() ? 0 : argument->getArgNo();
616 insertAllocsOrPushWorklist(callBase->getArgOperand(pos));
617 }
618 }
619 }
620 else if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(curValue))
621 {
622 ABORT_IFNOT(!callBase->doesNotReturn(), "callbase does not return:" + dumpValueAndDbgInfo(callBase));
623 if (Function *callee = callBase->getCalledFunction())
624 {
625 if (!callee->isDeclaration())
626 {
627
629 const BasicBlock* exitBB = llvmmodule->getFunExitBB(callee);
630 assert (exitBB && "exit bb is not a basic block?");
631 const Value *pValue = &exitBB->back();
632 const auto *retInst = SVFUtil::dyn_cast<ReturnInst>(pValue);
633 ABORT_IFNOT(retInst && retInst->getReturnValue(), "not return inst?");
634 insertAllocsOrPushWorklist(retInst->getReturnValue());
635 }
636 }
637 }
638 if (canUpdate)
639 {
641 }
642 }
644 if (srcs.empty())
645 {
646 WARN_MSG("Cannot find allocation: " + dumpValueAndDbgInfo(var));
647 }
648 return srcs;
649}
unsigned u32_t
Definition CommandLine.h:18
#define ABORT_IFNOT(condition, msg)
#define WARN_MSG(msg)
static LLVMModuleSet * getLLVMModuleSet()
Definition LLVMModule.h:129
ValueToSources _valueToAllocs
bool isAlloc(const SVF::Value *val)
is allocation (stack, static, heap)
std::string dumpValueAndDbgInfo(const Value *val)
Definition LLVMUtil.cpp:622
constexpr std::remove_reference< T >::type && move(T &&t) noexcept
Definition SVFUtil.h:420
llvm::CallBase CallBase
Definition BasicTypes.h:146
llvm::BasicBlock BasicBlock
Definition BasicTypes.h:86
llvm::Function Function
Definition BasicTypes.h:85
llvm::Value Value
LLVM Basic classes.
Definition BasicTypes.h:82
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74
llvm::StoreInst StoreInst
Definition BasicTypes.h:148

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

823{
824
825 // consult cache
828 {
829 return tIt->second;
830 }
831
832 // simulate the call stack, the second element indicates whether we should update sources for current value
834 Set<ValueBoolPair> visited;
835 workList.push({startValue, false});
836 while (!workList.empty())
837 {
838 auto curPair = workList.pop();
839 if (visited.count(curPair)) continue;
840 visited.insert(curPair);
841 const Value *curValue = curPair.first;
842 bool canUpdate = curPair.second;
843
844 Set<const Value *> sources;
845 auto insertSource = [&sources, &canUpdate](const Value *source)
846 {
847 if (canUpdate) sources.insert(source);
848 };
849 auto insertSourcesOrPushWorklist = [this, &sources, &workList, &canUpdate](const auto &pUser)
850 {
852 if (canUpdate)
853 {
854 if (vIt != _valueToAllocOrClsNameSources.end() && !vIt->second.empty())
855 {
856 sources.insert(vIt->second.begin(), vIt->second.end());
857 }
858 }
859 else
860 {
861 if (vIt == _valueToAllocOrClsNameSources.end()) workList.push({pUser, false});
862 }
863 };
864
866 {
867 workList.push({curValue, true});
868 }
869
870 // If current value is an instruction inside a constructor/destructor/template, use it as a source
871 if (const auto *inst = SVFUtil::dyn_cast<Instruction>(curValue))
872 {
873 if (const auto *parent = inst->getFunction())
874 {
876 }
877 }
878
879 // If the current value is an object (global, heap, stack, etc) or name source (constructor/destructor,
880 // a C++ dynamic cast, or a template function), use it as a source
882 {
884 }
885
886 // Explore the current value further depending on the type of the value; use cached values if possible
887 if (const auto *getElementPtrInst = SVFUtil::dyn_cast<GetElementPtrInst>(curValue))
888 {
890 }
891 else if (const auto *bitCastInst = SVFUtil::dyn_cast<BitCastInst>(curValue))
892 {
894 }
895 else if (const auto *phiNode = SVFUtil::dyn_cast<PHINode>(curValue))
896 {
897 for (const auto *op : phiNode->operand_values())
898 {
900 }
901 }
902 else if (const auto *loadInst = SVFUtil::dyn_cast<LoadInst>(curValue))
903 {
904 for (const auto *user : loadInst->getPointerOperand()->users())
905 {
906 if (const auto *storeInst = SVFUtil::dyn_cast<StoreInst>(user))
907 {
908 if (storeInst->getPointerOperand() == loadInst->getPointerOperand())
909 {
910 insertSourcesOrPushWorklist(storeInst->getValueOperand());
911 }
912 }
913 }
914 }
915 else if (const auto *argument = SVFUtil::dyn_cast<Argument>(curValue))
916 {
917 for (const auto *user: argument->getParent()->users())
918 {
919 if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(user))
920 {
921 // skip function as parameter
922 // e.g., call void @foo(%struct.ssl_ctx_st* %9, i32 (i8*, i32, i32, i8*)* @passwd_callback)
923 if (callBase->getCalledFunction() != argument->getParent()) continue;
924 u32_t pos = argument->getParent()->isVarArg() ? 0 : argument->getArgNo();
926 }
927 }
928 }
929 else if (const auto *callBase = SVFUtil::dyn_cast<CallBase>(curValue))
930 {
931 ABORT_IFNOT(!callBase->doesNotReturn(), "callbase does not return:" + dumpValueAndDbgInfo(callBase));
932 if (const auto *callee = callBase->getCalledFunction())
933 {
934 if (!callee->isDeclaration())
935 {
937 const BasicBlock* exitBB = llvmmodule->getFunExitBB(callee);
938 assert (exitBB && "exit bb is not a basic block?");
939 const Value *pValue = &exitBB->back();
940 const auto *retInst = SVFUtil::dyn_cast<ReturnInst>(pValue);
941 ABORT_IFNOT(retInst && retInst->getReturnValue(), "not return inst?");
942 insertSourcesOrPushWorklist(retInst->getReturnValue());
943 }
944 }
945 }
946
947 // If updating is allowed; store the gathered sources as sources for the current value in the cache
948 if (canUpdate)
949 {
951 }
952 }
953
955}
ValueToSources _valueToAllocOrClsNameSources
bool isClsNameSource(const Value *val)
Definition CppUtil.cpp:860

◆ 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:633

◆ fwFindClsNameSources()

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

forward find class name sources starting from an allocation

Definition at line 957 of file ObjTypeInference.cpp.

958{
959 assert(startValue && "startValue was null?");
960
961 // consult cache
963 if (tIt != _objToClsNameSources.end())
964 {
965 return tIt->second;
966 }
967
968 Set<const CallBase *> sources;
969
970 // Lambda for adding a callee to the sources iff it is a constructor/destructor/template/dyncast
971 auto inferViaCppCall = [&sources](const CallBase *caller)
972 {
973 if (!caller) return;
974 if (isClsNameSource(caller)) sources.insert(caller);
975 };
976
977 // Find all calls of starting val (or through cast); add as potential source iff applicable
978 for (const auto *user : startValue->users())
979 {
980 if (const auto *caller = SVFUtil::dyn_cast<CallBase>(user))
981 {
983 }
984 else if (const auto *bitcast = SVFUtil::dyn_cast<BitCastInst>(user))
985 {
986 for (const auto *cast_user : bitcast->users())
987 {
988 if (const auto *caller = SVFUtil::dyn_cast<CallBase>(cast_user))
989 {
991 }
992 }
993 }
994 }
995
996 // Store sources in cache for starting value & return the found sources
998}
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 201 of file ObjTypeInference.cpp.

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

◆ getArgPosInCall()

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

Definition at line 699 of file ObjTypeInference.cpp.

700{
701 assert(callBase->hasArgument(arg) && "callInst does not have argument arg?");
702 auto it = std::find(callBase->arg_begin(), callBase->arg_end(), arg);
703 assert(it != callBase->arg_end() && "Didn't find argument?");
704 return std::distance(callBase->arg_begin(), it);
705}

◆ getLLVMCtx()

LLVMContext & ObjTypeInference::getLLVMCtx ( )

Definition at line 125 of file ObjTypeInference.cpp.

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

◆ 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 for (const auto& use: var->users())
153 {
154 if (const CallBase* cs = SVFUtil::dyn_cast<CallBase>(use))
155 {
156 if (const Function* calledFun = cs->getCalledFunction())
158 {
159 assert(cs->getNumOperands() > 1 && "arguments should be greater than 1");
160 const Value* dst = cs->getArgOperand(0);
161 const Value* src = cs->getArgOperand(1);
162 if(calledFun->getName().find("iconv") != std::string::npos)
163 dst = cs->getArgOperand(3), src = cs->getArgOperand(1);
164
165 if (var == dst) return inferPointsToType(src);
166 else if (var == src) return inferPointsToType(dst);
167 else ABORT_MSG("invalid memcpy call");
168 }
169 }
170 }
171 }
172 return res;
173}
#define ABORT_MSG(msg)
const Type * inferPointsToType(const Value *var)
bool isMemcpyExtFun(const Function *fun)
Definition LLVMUtil.cpp:388

◆ inferPointsToType()

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

Definition at line 175 of file ObjTypeInference.cpp.

176{
177 if (isAlloc(var)) return fwInferObjType(var);
180 if (sources.empty())
181 {
182 // cannot find allocation, try to fw infer starting from var
183 types.insert(fwInferObjType(var));
184 }
185 else
186 {
187 for (const auto &source: sources)
188 {
189 types.insert(fwInferObjType(source));
190 }
191 }
193 ABORT_IFNOT(largestTy, "return type cannot be null");
194 return largestTy;
195}
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 749 of file ObjTypeInference.cpp.

750{
751 auto it = _thisPtrClassNames.find(thisPtr);
752 if (it != _thisPtrClassNames.end()) return it->second;
753
755
756 // Lambda for checking a function is a valid name source & extracting a class name from it
757 auto addNamesFromFunc = [&names](const Function *func) -> void
758 {
759 ABORT_IFNOT(isClsNameSource(func), "Func is invalid class name source: " + dumpValueAndDbgInfo(func));
760 for (const auto &name : extractClsNamesFromFunc(func)) names.insert(name);
761 };
762
763 // Lambda for getting callee & extracting class name for calls to constructors/destructors/template funcs
764 auto addNamesFromCall = [&names, &addNamesFromFunc](const CallBase *call) -> void
765 {
766 ABORT_IFNOT(isClsNameSource(call), "Call is invalid class name source: " + dumpValueAndDbgInfo(call));
767
768 const auto *func = call->getCalledFunction();
769 if (isDynCast(func)) names.insert(extractClsNameFromDynCast(call));
771 };
772
773 // Walk backwards to find all valid source sites for the pointer (e.g. stack/global/heap variables)
774 for (const auto &val: bwFindAllocOrClsNameSources(thisPtr))
775 {
776 // A source site is either a constructor/destructor/template function from which the class name can be
777 // extracted; a call to a C++ constructor/destructor/template function from which the class name can be
778 // extracted; or an allocation site of an object (i.e. a stack/global/heap variable), from which a
779 // forward walk can be performed to find calls to C++ constructor/destructor/template functions from
780 // which the class' name can then be extracted; skip starting pointer
781 if (val == thisPtr) continue;
782
783 if (const auto *func = SVFUtil::dyn_cast<Function>(val))
784 {
785 // Constructor/destructor/template func; extract name from func directly
787 }
788 else if (isClsNameSource(val))
789 {
790 // Call to constructor/destructor/template func; get callee; extract name from callee
791 ABORT_IFNOT(SVFUtil::isa<CallBase>(val), "Call source site is not a callbase: " + dumpValueAndDbgInfo(val));
792 addNamesFromCall(SVFUtil::cast<CallBase>(val));
793 }
794 else if (isAlloc(val))
795 {
796 // Stack/global/heap allocation site; walk forward; find constructor/destructor/template calls
797 ABORT_IFNOT((SVFUtil::isa<AllocaInst, CallBase, GlobalVariable>(val)),
798 "Alloc site source is not a stack/heap/global variable: " + dumpValueAndDbgInfo(val));
799 for (const auto *src : fwFindClsNameSources(val))
800 {
801 if (const auto *func = SVFUtil::dyn_cast<Function>(src)) addNamesFromFunc(func);
802 else if (const auto *call = SVFUtil::dyn_cast<CallBase>(src)) addNamesFromCall(call);
803 else ABORT_MSG("Source site from forward walk is invalid: " + dumpValueAndDbgInfo(src));
804 }
805 }
806 else
807 {
808 ERR_MSG("Unsupported source type found:" + dumpValueAndDbgInfo(val));
809 }
810 }
811
813}
#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:918
Set< std::string > extractClsNamesFromFunc(const Function *foo)
extract class name from the c++ function name, e.g., constructor/destructors
Definition CppUtil.cpp:706
bool isDynCast(const Function *foo)
whether foo is a cpp dyncast function
Definition CppUtil.cpp:908

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

652{
653 return LLVMUtil::isObject(val);
654}
bool isObject(const Value *ref)
Return true if this value refers to a object.
Definition LLVMUtil.cpp:59

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

725{
727 if (SVFUtil::isa<ArrayType>(objTy))
729 else if (const auto *st = SVFUtil::dyn_cast<StructType>(objTy))
730 {
733 if (!classTyHasVTable(st))
735 }
736 return num;
737}
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition Options.h:38
u32_t getNumOfElements(const Type *ety)
Return size of this object based on LLVM value.
Definition LLVMUtil.cpp:295
bool classTyHasVTable(const StructType *ty)
Definition CppUtil.cpp:569

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

709{
710 if (objTys.empty()) return nullptr;
711 // map type size to types from with key in descending order
713 for (const Type *ty: objTys)
714 {
716 }
717 assert(!typeSzToTypes.empty() && "typeSzToTypes cannot be empty");
719 std::tie(std::ignore, largestTypes) = *typeSzToTypes.begin();
720 assert(!largestTypes.empty() && "largest element cannot be empty");
721 return *largestTypes.begin();
722}
u32_t objTyToNumFields(const Type *objTy)

◆ typeSizeDiffTest()

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

Definition at line 685 of file ObjTypeInference.cpp.

686{
687#if TYPE_DEBUG
691 {
692 ERR_MSG("original type is:" + dumpType(oTy));
693 ERR_MSG("infered type is:" + dumpType(iTy));
694 ABORT_MSG("wrong type, trace ID is " + std::to_string(traceId) + ":" + dumpValueAndDbgInfo(val));
695 }
696#endif
697}
std::string dumpType(const Type *type)
Definition LLVMUtil.cpp:611
static Type * getPtrElementType(const PointerType *pty)
Definition LLVMUtil.h:130

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

661{
662 if (const Function *func = cs->getCalledFunction())
663 {
664 if (func->getName().find(TYPEMALLOC) != std::string::npos)
665 {
666 const Type *objType = fwInferObjType(cs);
667 const auto *pInt =
668 SVFUtil::dyn_cast<llvm::ConstantInt>(cs->getOperand(1));
669 assert(pInt && "the second argument is a integer");
672 SVFUtil::outs() << SVFUtil::sucMsg("\t SUCCESS :") << dumpValueAndDbgInfo(cs)
673 << SVFUtil::pasMsg(" TYPE: ")
674 << dumpType(objType) << "\n";
675 else
676 {
677 SVFUtil::errs() << SVFUtil::errMsg("\t FAILURE :") << ":" << dumpValueAndDbgInfo(cs) << " TYPE: "
678 << dumpType(objType) << "\n";
679 abort();
680 }
681 }
682 }
683}
const std::string TYPEMALLOC
std::pair< s64_t, u64_t > getIntegerValue(const ConstantInt *intValue)
Definition LLVMUtil.h:82
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: