49 AccessPath accessPath;
50 const SVFType* elementType;
57bool parseAnnotationArgIndex(
const std::string& annotation,
const std::string& prefix,
58 u32_t& argIdx,
size_t& end)
60 const size_t start = annotation.find(prefix);
61 if (start == std::string::npos)
64 end = start + prefix.size();
65 if (end >= annotation.size() || annotation[end] <
'0' || annotation[end] >
'9')
71 argIdx = argIdx * 10 +
static_cast<u32_t>(annotation[end] -
'0');
74 while (end < annotation.size() && annotation[end] >=
'0' && annotation[end] <=
'9');
81bool parseNondetArgStoreAtExtCall(
const std::string& annotation,
u32_t& firstArg)
84 return parseAnnotationArgIndex(annotation,
"STORE_TOP:Arg", firstArg, end) &&
85 end < annotation.size() && annotation[end] ==
'+';
93bool parseScanfFormatArg(
const std::string& annotation,
u32_t& formatArg)
96 return parseAnnotationArgIndex(annotation,
"SCANF:FormatArg", formatArg, end);
101bool scanfMayStorePointer(
const CallBase* cs,
u32_t formatArg)
105 if (!glob || !glob->isConstant() || !glob->hasDefinitiveInitializer())
108 if (!data || !data->isCString())
111 auto format = data->getAsCString();
112 auto in = [](
const std::string& set,
char c)
114 return set.find(c) != std::string::npos;
121 const size_t percent =
format.find(
'%');
122 if (percent ==
format.npos)
125 if (
format.consume_front(
"%"))
129 const bool suppressed =
format.consume_front(
"*");
131 const auto modifiers =
format.take_front(
format.find_first_not_of(
"hljztLqm"));
135 const char conversion =
format.front();
138 if (!in(
"diouxXaAeEfFgGsScCnp[", conversion))
142 const bool allocatesString = modifiers.contains(
'm') ||
143 (conversion ==
'a' && !
format.empty() && in(
"sS[",
format.front()));
144 if (!suppressed && (conversion ==
'p' || allocatesString))
147 if (conversion ==
'[')
151 format.consume_front(
"^");
152 format.consume_front(
"]");
153 const size_t end =
format.find(
']');
162bool hasNondetArgStoreAtExtCall(
const CallICFGNode* callICFGNode)
165 if (extFun ==
nullptr)
168 for (
const std::string& annotation :
172 if (parseNondetArgStoreAtExtCall(annotation, firstArg))
178void collectMemcpyFields(
179 const Type* llvmType,
183 std::vector<MemcpyField>& fields,
187 if (llvmType ==
nullptr || svfType ==
nullptr)
196 if (fields.size() >= maxFields)
201 fields.push_back({baseByteOffset,
AccessPath(baseFldIdx), svfType});
212 assert(svfStructType &&
"an LLVM struct type maps to an SVFStructType");
215 i < structType->getNumElements() && fields.size() < maxFields; ++i)
217 const Type* elemLLVMType = structType->getElementType(i);
218 const SVFType* elemSVFType = svfStructType->getFieldTypes()[i];
219 if (elemSVFType ==
nullptr)
221 APOffset elemByteOffset = baseByteOffset +
static_cast<APOffset>(layout->getElementOffset(i));
223 collectMemcpyFields(elemLLVMType, elemSVFType, dl, pag, fields, elemByteOffset, elemFldIdx);
231 assert(svfArrayType &&
"an LLVM array type maps to an SVFArrayType");
232 const Type* elemLLVMType = arrayType->getElementType();
233 const SVFType* elemSVFType = svfArrayType->getTypeOfElement();
234 if (elemSVFType ==
nullptr)
236 const APOffset elemByteSize =
static_cast<APOffset>(dl.getTypeAllocSize(
const_cast<Type*
>(elemLLVMType)));
238 i < arrayType->getNumElements() && fields.size() < maxFields; ++i)
240 APOffset elemByteOffset = baseByteOffset + i * elemByteSize;
242 collectMemcpyFields(elemLLVMType, elemSVFType, dl, pag, fields, elemByteOffset, elemFldIdx);
247std::vector<MemcpyField> getMemcpyFields(
const Value* value,
const Type* llvmType,
const SVFType* svfType)
249 std::vector<MemcpyField> fields;
252 const DataLayout& dl = mset->getMainLLVMModule()->getDataLayout();
253 collectMemcpyFields(llvmType, svfType, dl, pag, fields);
257const Type* getMemcpyLayoutType(
const Value* baseValue,
const Type* fallbackType)
259 if (
const auto* allocaInst = llvm::dyn_cast_or_null<AllocaInst>(baseValue))
260 return allocaInst->getAllocatedType();
262 if (
const auto* global = llvm::dyn_cast_or_null<GlobalVariable>(baseValue))
263 return global->getValueType();
283 numOfElems = (numOfElems > szIntVal.first) ? szIntVal.first : numOfElems;
294 for(
u32_t ei = 0; ei < numOfElems; ei++)
309 fields.push_back(ls);
325 std::vector<AccessPath> fields;
328 std::vector<AccessPath> srcFields;
329 std::vector<AccessPath> dstFields;
332 if(srcFields.size() > dstFields.size())
338 u32_t sz = fields.size();
352 const Type* dstLayoutType = getMemcpyLayoutType(dstBase, dtype);
353 const Type* srcLayoutType = getMemcpyLayoutType(srcBase, stype);
354 const bool hasRemappedGlobalBase =
357 const bool useByteLayoutMemcpy =
358 hasRemappedGlobalBase || (dstLayoutType != dtype) || (srcLayoutType != stype);
359 if (useByteLayoutMemcpy)
363 std::vector<MemcpyField> dstMemcpyFields = getMemcpyFields(D, dstLayoutType, dstSVFType);
364 std::vector<MemcpyField> srcMemcpyFields = getMemcpyFields(S, srcLayoutType, srcSVFType);
365 if (!dstMemcpyFields.empty() && !srcMemcpyFields.empty())
367 std::unordered_map<APOffset, MemcpyField> srcFieldsByByteOffset;
368 for (
const auto& field : srcMemcpyFields)
369 srcFieldsByByteOffset.emplace(field.byteOffset, field);
372 APOffset copyBytes = std::min<APOffset>(
373 static_cast<APOffset>(dl.getTypeAllocSize(
const_cast<Type*
>(dstLayoutType))),
374 static_cast<APOffset>(dl.getTypeAllocSize(
const_cast<Type*
>(srcLayoutType))));
378 copyBytes = std::min(copyBytes,
static_cast<APOffset>(szIntVal.first));
381 for (
const auto& dstField : dstMemcpyFields)
383 if (dstField.byteOffset >= copyBytes)
385 auto it = srcFieldsByByteOffset.find(dstField.byteOffset);
386 if (it == srcFieldsByByteOffset.end())
389 NodeID dField =
getGepValVar(dstFieldBase, dstField.accessPath, dstField.elementType);
390 NodeID sField =
getGepValVar(srcFieldBase, it->second.accessPath, it->second.elementType);
404 fields[
index].getConstantStructFldIdx());
406 fields[
index].getConstantStructFldIdx());
422 for (
const std::string& annotation :
425 u32_t annotatedFormatArg = 0;
426 if (parseScanfFormatArg(annotation, annotatedFormatArg))
428 if (annotatedFormatArg < cs->arg_size())
430 src =
pag->getBlkPtr();
431 if (!scanfMayStorePointer(cs, annotatedFormatArg))
445 if (!parseNondetArgStoreAtExtCall(annotation, firstArg))
447 if (firstArg >= cs->arg_size())
450 for (
u32_t argIdx = firstArg; argIdx < cs->arg_size(); ++argIdx)
451 storeTopArgs.insert(argIdx);
455 for (
u32_t argIdx : storeTopArgs)
457 const Value* arg = cs->getArgOperand(argIdx);
458 if (!arg->getType()->isPointerTy())
461 const Type* storedType =
475 if (hasNondetArgStoreAtExtCall(callICFGNode))
488 Value* arg = cs->getArgOperand(arg_pos);
489 if (cs->getArgOperand(arg_pos)->getType()->isPointerTy())
494 if (vnArg && dummy && obj)
502 writeWrnMsg(
"Arg receiving new object must be pointer type");
509 if(callee->getName().find(
"iconv") != std::string::npos)
511 else if(callee->getName().find(
"bcopy") != std::string::npos)
513 if(cs->arg_size() == 3)
520 else if (
llvmModuleSet()->hasExtFuncAnnotation(callee,
"STRLEN"))
525 std::vector<AccessPath> fields;
526 const Value* arg = cs->getArgOperand(0);
530 const SVFType* elementType =
pag->getFlatternedElemType(
532 field.getConstantStructFldIdx());
541 std::vector<AccessPath> dstFields;
543 u32_t sz = dstFields.size();
549 dstFields[
index].getConstantStructFldIdx());
556 else if(callee->getName().compare(
"dlsym") == 0)
571 const Value* src = cs->getArgOperand(1);
588 if (
const Function *fn = getHookFn(src))
594 else if(callee->getName().find(
"_ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_") != std::string::npos)
597 assert(cs->arg_size() == 4 &&
"_Rb_tree_insert_and_rebalance should have 4 arguments.\n");
606 vector<AccessPath> fields =
pag->getTypeLocSetsMap(vnArg3).second;
612 if((
u32_t)i >= fields.size())
614 const SVFType* elementType =
pag->getFlatternedElemType(
pag->getTypeLocSetsMap(vnArg3).first,
615 fields[i].getConstantStructFldIdx());
632 assert((forkedFun->
arg_size() <= 2) &&
"Size of formal parameter of start routine should be one");
char const int const cJSON_bool format
APOffset getConstantStructFldIdx() const
Get methods.
bool addOffsetVarAndGepTypePair(const ValVar *var, const SVFType *gepIterType)
Class representing a function argument variable in the SVFIR.
const FunObjVar * getCalledFunction() const
static ExtAPI * getExtAPI()
const ArgValVar * getArg(u32_t idx) const
virtual const FunObjVar * getFunction() const
Get containing function, or null for globals/constants.
const FunObjVar * getDefFunForMultipleModule() const
u32_t getFlattenedElemIdx(const SVFType *T, u32_t origId)
Flattened element idx of an array or struct by considering stride.
NodeID getValueNode(const Value *V)
Module * getMainLLVMModule() const
static LLVMModuleSet * getLLVMModuleSet()
void addToSVFVar2LLVMValueMap(const Value *val, SVFValue *svfBaseNode)
SVFType * getSVFType(const Type *T)
Get or create SVFType and typeinfo.
CallICFGNode * getCallICFGNode(const Instruction *cs)
get a call node
NodeID getObjectNode(const Value *V)
LLVMContext & getContext() const
ObjTypeInference * getTypeInference()
static NodeIDAllocator * get(void)
Return (singleton) allocator.
const Type * inferObjType(const Value *var)
get or infer the type of the object pointed by the value
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
SVFIR * getPAG() const
Return SVFIR.
void addStoreEdge(NodeID src, NodeID dst)
Add Store edge.
void addLoadEdge(NodeID src, NodeID dst)
Add Load edge.
virtual void handleExtCall(const CallBase *cs, const Function *callee)
AddrStmt * addAddrWithHeapSz(NodeID src, NodeID dst, const CallBase *cs)
Add Address edge from ext call with args like "%5 = call i8* @malloc(i64 noundef 5)".
LLVMModuleSet * llvmModuleSet()
void addThreadForkEdge(NodeID src, NodeID dst, const CallICFGNode *cs, const FunEntryICFGNode *entry)
Add Thread fork edge for parameter passing.
AccessPath getAccessPathFromBaseNode(NodeID nodeId)
const Value * getBaseValueForExtArg(const Value *V)
Get the base value of (i8* src and i8* dst) for external argument (e.g. memcpy(i8* dst,...
virtual void handleNondetArgStoreAtExtCall(const CallBase *cs, const CallICFGNode *callICFGNode)
NodeID getDirectAccessFieldZeroValVar(const Value *ptr, const Type *accessTy)
virtual const Type * getBaseTypeAndFlattenedFields(const Value *V, std::vector< AccessPath > &fields, const Value *szValue)
Handle external call.
CopyStmt * addCopyEdge(NodeID src, NodeID dst, CopyStmt::CopyKind kind)
NodeID getValueNode(const Value *V)
Get different kinds of node.
virtual void addComplexConsForExt(Value *D, Value *S, const Value *sz)
NodeID getGepValVar(const Value *val, const AccessPath &ap, const SVFType *elementType)
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
static SVFType * getSVFInt8Type()
NodeID getId() const
Get ID.
virtual const SVFType * getType() const
virtual bool isPointer() const
Check if this variable represents a pointer.
void collectSym(const Value *val)
const Function * getProgFunction(const std::string &funName)
Get program entry function from module.
const Value * stripConstantCasts(const Value *val)
Strip off the constant casts.
bool isHeapAllocExtCallViaRet(const Instruction *inst)
bool isMemcpyExtFun(const Function *fun)
std::pair< s64_t, u64_t > getIntegerValue(const ConstantInt *intValue)
bool isConstDataOrAggData(const Value *val)
Return true if the value refers to constant data, e.g., i32 0.
bool isHeapAllocExtCallViaArg(const Instruction *inst)
bool isMemsetExtFun(const Function *fun)
bool isObject(const Value *ref)
Return true if this value refers to a object.
u32_t getHeapAllocHoldingArgPosition(const Function *fun)
std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > cast(const Y &Val)
LLVM_NODISCARD bool isa(const Y &Val)
bool isThreadForkCall(const CallICFGNode *inst)
void writeWrnMsg(const std::string &msg)
Writes a message run through wrnMsg.
const ValVar * getActualParmAtForkSite(const CallICFGNode *cs)
Return sole argument of the thread routine.
const ValVar * getForkedFun(const CallICFGNode *inst)
Return thread fork function.
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
llvm::DataLayout DataLayout
llvm::GlobalVariable GlobalVariable
llvm::StructType StructType
LLVM types.
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
llvm::StructLayout StructLayout
llvm::Value Value
LLVM Basic classes.
llvm::GetElementPtrInst GetElementPtrInst
llvm::ConstantDataArray ConstantDataArray
llvm::ConstantInt ConstantInt
llvm::LLVMContext LLVMContext