Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1st PR of more precise ObjTypeInfo #1255

Merged
merged 2 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion svf-llvm/include/SVF-LLVM/SymbolTableBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class SymbolTableBuilder
void buildMemModel(SVFModule* svfModule);

/// Return size of this object based on LLVM value
u32_t getObjSize(const Type* type);
u32_t getNumOfElements(const Type* ety);


protected:

Expand Down Expand Up @@ -93,6 +94,9 @@ class SymbolTableBuilder
/// Analyse types of heap and static objects
void analyzeStaticObjType(ObjTypeInfo* typeinfo, const Value* val);

/// Analyze byte size of heap alloc function (e.g. malloc/calloc/...)
u32_t analyzeHeapAllocByteSize(const Value* val);

///Get a reference to the components of struct_info.
/// Number of flattened elements of an array or struct
u32_t getNumOfFlattenElements(const Type* T);
Expand Down
132 changes: 121 additions & 11 deletions svf-llvm/lib/SymbolTableBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,86 @@
typeinfo->setFlag(ObjTypeInfo::HASPTR_OBJ);
}

/*!
* Analyze byte size of heap alloc function (e.g. malloc/calloc/...)
* 1) __attribute__((annotate("ALLOC_RET"), annotate("AllocSize:Arg0")))
void* safe_malloc(unsigned long size).
Byte Size is the size(Arg0)
2)__attribute__((annotate("ALLOC_RET"), annotate("AllocSize:Arg0*Arg1")))
char* safecalloc(int a, int b)
Byte Size is a(Arg0) * b(Arg1)
3)__attribute__((annotate("ALLOC_RET"), annotate("UNKNOWN")))
void* __sysv_signal(int a, void *b)
Byte Size is Unknown
If all required arg values are constant, byte Size is also constant,
otherwise return ByteSize 0
*/
u32_t SymbolTableBuilder::analyzeHeapAllocByteSize(const Value* val) {
if(const llvm::CallInst* callInst = llvm::dyn_cast<llvm::CallInst>(val))
{
if (const llvm::Function* calledFunction =
callInst->getCalledFunction())
{
const SVFFunction* svfFunction =
LLVMModuleSet::getLLVMModuleSet()->getSVFFunction(
calledFunction);
std::vector<const Value*> args;
// Heap alloc functions have annoation like "AllocSize:Arg1"
for (std::string annotation : svfFunction->getAnnotations())
{
if (annotation.find("AllocSize:") != std::string::npos)
{
std::string allocSize = annotation.substr(10);
std::stringstream ss(allocSize);
std::string token;
// Analyaze annotation string and attract Arg list
while (std::getline(ss, token, '*'))
{
if (token.rfind("Arg", 0) == 0)
{
u32_t argIndex;
std::istringstream(token.substr(3)) >> argIndex;
if (argIndex < callInst->getNumOperands() - 1)
{
args.push_back(
callInst->getArgOperand(argIndex));
}
}
}
}
}
u64_t product = 1;
if (args.size() > 0)
{
// for annotations like "AllocSize:Arg0*Arg1"
for (const llvm::Value* arg : args)
{
if (const llvm::ConstantInt* constIntArg =
llvm::dyn_cast<llvm::ConstantInt>(arg))
{
// Multiply the constant Value if all Args are const
product *= constIntArg->getZExtValue();
}
else
{
// if Arg list has non-const value, return 0 to indicate it is non const byte size
return 0;
}
}
// If all the Args are const, return product
return product;
}
else
{
// for annotations like "AllocSize:UNKNOWN"
return 0;
}
}
}
// if it is not CallInst or CallInst has no CalledFunction, return 0 to indicate it is non const byte size
return 0;
}

/*!
* Analyse types of heap and static objects
*/
Expand Down Expand Up @@ -714,52 +794,76 @@
const Type* objTy)
{

u32_t objSize = 1;
u32_t elemNum = 1;
// init byteSize = 0, If byteSize is changed in the following process,
// it means that ObjTypeInfo has a Constant Byte Size
u32_t byteSize = 0;
// Global variable
// if val is Function Obj, byteSize is not set
if (SVFUtil::isa<Function>(val))
{
typeinfo->setFlag(ObjTypeInfo::FUNCTION_OBJ);
analyzeObjType(typeinfo,val);
objSize = getObjSize(objTy);
elemNum = getNumOfElements(objTy);
}
/// if val is AllocaInst, byteSize is Type's LLVM ByteSize * ArraySize
/// e.g. alloc i32, 10. byteSize is 4 (i32's size) * 10 (ArraySize) = 40
else if(const AllocaInst* allocaInst = SVFUtil::dyn_cast<AllocaInst>(val))
{
typeinfo->setFlag(ObjTypeInfo::STACK_OBJ);
analyzeObjType(typeinfo,val);
/// This is for `alloca <ty> <NumElements>`. For example, `alloca i64 3` allocates 3 i64 on the stack (objSize=3)
/// In most cases, `NumElements` is not specified in the instruction, which means there is only one element (objSize=1).
if(const ConstantInt* sz = SVFUtil::dyn_cast<ConstantInt>(allocaInst->getArraySize()))
objSize = sz->getZExtValue() * getObjSize(objTy);
{
elemNum = sz->getZExtValue() * getNumOfElements(objTy);
byteSize = sz->getZExtValue() * typeinfo->getType()->getLLVMByteSize();
}
/// if ArraySize is not constant, byteSize is not static determined.
else
objSize = getObjSize(objTy);
{
elemNum = getNumOfElements(objTy);
byteSize = 0;
}
}
/// if val is GlobalVar, byteSize is Type's LLVM ByteSize
/// All GlobalVariable must have constant size
else if(SVFUtil::isa<GlobalVariable>(val))
{
typeinfo->setFlag(ObjTypeInfo::GLOBVAR_OBJ);
if(isConstantObjSym(val))
typeinfo->setFlag(ObjTypeInfo::CONST_GLOBAL_OBJ);
analyzeObjType(typeinfo,val);
objSize = getObjSize(objTy);
elemNum = getNumOfElements(objTy);
byteSize = typeinfo->getType()->getLLVMByteSize();
}
/// if val is heap alloc
else if (SVFUtil::isa<Instruction>(val) &&
isHeapAllocExtCall(
LLVMModuleSet::getLLVMModuleSet()->getSVFInstruction(
SVFUtil::cast<Instruction>(val))))
{
analyzeHeapObjType(typeinfo,val);
// Heap object, label its field as infinite here
objSize = typeinfo->getMaxFieldOffsetLimit();
elemNum = typeinfo->getMaxFieldOffsetLimit();
// analyze heap alloc like (malloc/calloc/...), the alloc functions have
// annotation like "AllocSize:Arg1". Please refer to extapi.c.
// e.g. calloc(4, 10), annotation is "AllocSize:Arg0*Arg1",
// it means byteSize = 4 (Arg0) * 10 (Arg1) = 40
byteSize = analyzeHeapAllocByteSize(val);
}
else if(ArgInProgEntryFunction(val))
{
analyzeStaticObjType(typeinfo,val);
// user input data, label its field as infinite here
objSize = typeinfo->getMaxFieldOffsetLimit();
elemNum = typeinfo->getMaxFieldOffsetLimit();
byteSize = typeinfo->getType()->getLLVMByteSize();

Check warning on line 860 in svf-llvm/lib/SymbolTableBuilder.cpp

View check run for this annotation

Codecov / codecov/patch

svf-llvm/lib/SymbolTableBuilder.cpp#L859-L860

Added lines #L859 - L860 were not covered by tests
}
else if(LLVMUtil::isConstDataOrAggData(val))
{
typeinfo->setFlag(ObjTypeInfo::CONST_DATA);
objSize = getNumOfFlattenElements(val->getType());
elemNum = getNumOfFlattenElements(val->getType());
byteSize = typeinfo->getType()->getLLVMByteSize();

Check warning on line 866 in svf-llvm/lib/SymbolTableBuilder.cpp

View check run for this annotation

Codecov / codecov/patch

svf-llvm/lib/SymbolTableBuilder.cpp#L865-L866

Added lines #L865 - L866 were not covered by tests
}
else
{
Expand All @@ -768,14 +872,20 @@
}

// Reset maxOffsetLimit if it is over the total fieldNum of this object
if(typeinfo->getMaxFieldOffsetLimit() > objSize)
typeinfo->setNumOfElements(objSize);
if(typeinfo->getMaxFieldOffsetLimit() > elemNum)
typeinfo->setNumOfElements(elemNum);

// set ByteSize. If ByteSize > 0, this typeinfo has constant type.
// If ByteSize == 0, this typeinfo has 1) zero byte 2) non-const byte size
// If ByteSize>MaxFieldLimit, set MaxFieldLimit to the byteSize;
byteSize = Options::MaxFieldLimit() > byteSize? byteSize: Options::MaxFieldLimit();
typeinfo->setByteSizeOfObj(byteSize);
}

/*!
* Return size of this Object
*/
u32_t SymbolTableBuilder::getObjSize(const Type* ety)
u32_t SymbolTableBuilder::getNumOfElements(const Type* ety)
{
assert(ety && "type is null?");
u32_t numOfFields = 1;
Expand Down
Loading
Loading