Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
changes for hpcfi
Browse files Browse the repository at this point in the history
  • Loading branch information
Florian Kasten committed Sep 26, 2024
1 parent 6f42ece commit e5e23b1
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 21 deletions.
1 change: 0 additions & 1 deletion include/MemoryModel/SVFIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class SVFIR : public IRGraph
friend class SVFIRBuilder;
friend class ExternalPAG;
friend class PAGBuilderFromFile;
friend class TypeBasedHeapCloning;

public:
typedef Set<const CallICFGNode*> CallSiteSet;
Expand Down
5 changes: 5 additions & 0 deletions include/WPA/WPAPass.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ class WPAPass
return "WPAPass";
}

inline SVFG* getSVFG() const
{
return _svfg;
}

private:
/// Create pointer analysis according to specified kind and analyze the module.
void runPointerAnalysis(SVFModule* svfModule, u32_t kind);
Expand Down
4 changes: 4 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ add_llvm_library(Svf STATIC ${SOURCES} LINK_LIBS Cudd ${Z3_LIBRARIES})

link_directories(${CMAKE_BINARY_DIR}/lib/Cudd)

add_llvm_library(LLVMSvf MODULE BUILDTREE_ONLY ${SOURCES})
target_link_libraries(LLVMSvf PRIVATE Cudd)
add_dependencies(LLVMSvf intrinsics_gen)
add_dependencies(LLVMSvf opt)

if(DEFINED IN_SOURCE_BUILD)
add_dependencies(Svf intrinsics_gen)
Expand Down
2 changes: 1 addition & 1 deletion lib/Graphs/SVFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ void SVFG::getInterVFEdgesForIndirectCallSite(const CallICFGNode* callICFGNode,
if (fun_arg->isPointer() && cs_arg->isPointer())
getInterVFEdgeAtIndCSFromAPToFP(cs_arg, fun_arg, callICFGNode, csId, edges);
}
assert(funArgIt == funArgEit && "function has more arguments than call site");
//assert(funArgIt == funArgEit && "function has more arguments than call site");
if (callee->getLLVMFun()->isVarArg())
{
NodeID varFunArg = pag->getVarargNode(callee);
Expand Down
2 changes: 1 addition & 1 deletion lib/Graphs/VFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ void VFG::connectCallerAndCallee(const CallICFGNode* callBlockNode, const SVFFun
if (fun_arg->isPointer() && cs_arg->isPointer())
connectAParamAndFParam(cs_arg, fun_arg, callBlockNode, csId, edges);
}
assert(funArgIt == funArgEit && "function has more arguments than call site");
// assert(funArgIt == funArgEit && "function has more arguments than call site");
if (callee->getLLVMFun()->isVarArg())
{
NodeID varFunArg = pag->getVarargNode(callee);
Expand Down
2 changes: 1 addition & 1 deletion lib/MemoryModel/PointerAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ void PointerAnalysis::resolveIndCalls(const CallICFGNode* cs, const PointsTo& ta

/// if the arg size does not match then we do not need to connect this parameter
/// even if the callee is a variadic function (the first parameter of variadic function is its paramter number)
if(matchArgs(cs, callee) == false)
if(matchArgs(cs, callee) == false && !callee->isVarArg())
continue;

if(0 == getIndCallMap()[cs].count(callee))
Expand Down
7 changes: 6 additions & 1 deletion lib/MemoryModel/SymbolTableInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,10 @@ u32_t SymbolTableInfo::getFlattenedElemIdx(const Type *T, u32_t origId)
{
if(SVFUtil::isa<StructType>(T))
{
// if T is a packed struct, the actual type is probably array
if (SVFUtil::dyn_cast<StructType>(T)->isPacked() && !Options::ModelArrays) {
return 0;
}
std::vector<u32_t>& so = getStructInfoIter(T)->second->getFlattenedFieldIdxVec();
assert ((unsigned)origId < so.size() && !so.empty() && "Struct index out of bounds, can't get flattened index!");
return so[origId];
Expand Down Expand Up @@ -414,7 +418,8 @@ const Type* SymbolTableInfo::getFlatternedElemType(const Type* baseType, u32_t f
else
{
const std::vector<const Type*>& so = getStructInfoIter(baseType)->second->getFlattenFieldTypes();
assert (flatten_idx < so.size() && !so.empty() && "element index out of bounds or struct opaque type, can't get element type!");
if (!(flatten_idx < so.size() && !so.empty()))
return so[0];
return so[flatten_idx];
}
}
Expand Down
8 changes: 7 additions & 1 deletion lib/SVF-FE/CPPUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,13 @@ bool cppUtil::isLoadVtblInst(const LoadInst *loadInst)
*/
bool cppUtil::isVirtualCallSite(CallSite cs)
{
// the callsite must be an indirect one with at least one argument (this ptr)
// use metadata for indirect call detection instead
// metadata is always right, but svf still needs to find the virt-call pattern for its analysis
// function may only return true if both SVF + Metadata determine that it is a virtual call
bool is_virt_call = cs.getInstruction()->getMetadata("is_icall") == nullptr;
if (!is_virt_call)
return false;

if (cs.getCalledFunction() != nullptr || cs.arg_empty())
return false;

Expand Down
8 changes: 5 additions & 3 deletions lib/SVF-FE/LLVMUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,12 @@ const Value* LLVMUtil::getUniqueUseViaCastInst(const Value* val)
/// If type is void* (i8*) and val is only used at a bitcast instruction
if (IntegerType *IT = SVFUtil::dyn_cast<IntegerType>(getPtrElementType(type)))
{
if (IT->getBitWidth() == 8 && val->getNumUses()==1)
if (IT->getBitWidth() == 8)
{
const Use *u = &*val->use_begin();
return SVFUtil::dyn_cast<BitCastInst>(u->getUser());
for (const User* user: val->users()) {
if (const BitCastInst* bitCast = SVFUtil::dyn_cast<BitCastInst>(user))
return bitCast;
}
}
}
return nullptr;
Expand Down
97 changes: 88 additions & 9 deletions lib/SVF-FE/SVFIRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,32 @@ u32_t SVFIRBuilder::inferFieldIdxFromByteOffset(const llvm::GEPOperator* gepOp,
return 0;
}


// find the bitcast following an allocation and returns the corresponding type
Type *getStructTypeFromBitcast(const Value *V) {
for (const User *u : V->users()) {
if (const llvm::BitCastOperator* BC = SVFUtil::dyn_cast<llvm::BitCastOperator>(u)) {
if (PointerType *ptr_type = SVFUtil::dyn_cast<PointerType>(BC->getDestTy())) {
Type *deref_type = getPtrElementType(ptr_type);
if (SVFUtil::isa<StructType>(deref_type))
return deref_type;
}
}
else if (const StoreInst *SI = SVFUtil::dyn_cast<StoreInst>(u)) { // if src is i8*, dst may also get casted to i8*
if (const llvm::BitCastOperator* BC = SVFUtil::dyn_cast<llvm::BitCastOperator>(SI->getPointerOperand())) {
if (PointerType *ptr_type = SVFUtil::dyn_cast<PointerType>(BC->getSrcTy())) {
if (PointerType *ptr_type2 = SVFUtil::dyn_cast<PointerType>(getPtrElementType(ptr_type))) {
Type *deref_type = getPtrElementType(ptr_type2);
if (SVFUtil::isa<StructType>(deref_type))
return deref_type;
}
}
}
}
}
return nullptr;
}

/*!
* Return the object node offset according to GEP insn (V).
* Given a gep edge p = q + i, if "i" is a constant then we return its offset size
Expand All @@ -240,6 +266,7 @@ u32_t SVFIRBuilder::inferFieldIdxFromByteOffset(const llvm::GEPOperator* gepOp,
*/
bool SVFIRBuilder::computeGepOffset(const User *V, LocationSet& ls)
{
bool isConst = true;
assert(V);

const llvm::GEPOperator *gepOp = SVFUtil::dyn_cast<const llvm::GEPOperator>(V);
Expand All @@ -264,9 +291,14 @@ bool SVFIRBuilder::computeGepOffset(const User *V, LocationSet& ls)
// but we can distinguish different field of an array of struct, e.g. s[1].f1 is differet from s[0].f2
if(const ArrayType* arrTy = SVFUtil::dyn_cast<ArrayType>(gepTy))
{
if(!op || (arrTy->getArrayNumElements() <= (u32_t)op->getSExtValue()))
if(!op || (arrTy->getArrayNumElements() <= (u32_t)op->getSExtValue())) {
if (Options::ModelArrays)
isConst = false;
continue;
}
s32_t idx = op->getSExtValue();

// use precise info for constant arrays
u32_t offset = SymbolTableInfo::SymbolInfo()->getFlattenedElemIdx(arrTy, idx);
ls.setFldIdx(ls.accumulateConstantFieldIdx() + offset);
}
Expand All @@ -284,17 +316,41 @@ bool SVFIRBuilder::computeGepOffset(const User *V, LocationSet& ls)
// If its point-to target is struct or array, it's likely an array accessing (%result = gep %struct.A* %a, i32 %non-const-index)
// If its point-to target is single value (pointer arithmetic), then it's a variant gep (%result = gep i8* %p, i32 %non-const-index)
if(!op && gepTy->isPointerTy() && getPtrElementType(SVFUtil::dyn_cast<PointerType>(gepTy))->isSingleValueType())
return false;
isConst = false;

if (!op)
continue;

// The actual index
//s32_t idx = op->getSExtValue();
s32_t idx = op->getSExtValue();

// For pointer arithmetic we ignore the byte offset
// consider using inferFieldIdxFromByteOffset(geopOp,dataLayout,ls,idx)?
// ls.setFldIdx(ls.accumulateConstantFieldIdx() + inferFieldIdxFromByteOffset(geopOp,idx));
// handle GEPs such as the following: getelementptr %struct.StructA, %struct.StructA* %arrayinit.begin, i64 1
// byte offset GEPs are not handled here.
if (gepTy->isPointerTy()) { // should also work if arrays are not modeled
u32_t nr_fields = SymbolTableInfo::SymbolInfo()->getNumOfFlattenElements(gepTy->getPointerElementType());
ls.setFldIdx(ls.accumulateConstantFieldIdx() + idx * nr_fields);
}


// if type is i8*, the type may be wrong. find correct type and infer the correct field
LLVMContext &cxt = LLVMModuleSet::getLLVMModuleSet()->getContext();
if (gepTy == PointerType::getInt8PtrTy(cxt)) {
if (Type *struct_type = getStructTypeFromBitcast(gepOp->getPointerOperand())) {
std::vector<const Type*>& so = SymbolTableInfo::SymbolInfo()->getStructInfoIter(struct_type)->second->getFlattenElementTypes();
int byte_offset = 0;
for (unsigned int i = 0; i < so.size(); i++) {
if (byte_offset == idx) {
ls.setFldIdx(i);
break;
}
int size = dataLayout->getTypeAllocSize(const_cast<Type*>(so[i])).getFixedSize();
byte_offset += size + size % 8;
}
}
}
}
}
return true;
return isConst;
}

/*!
Expand Down Expand Up @@ -680,9 +736,16 @@ void SVFIRBuilder::visitCastInst(CastInst &inst)
DBOUT(DPAGBuild, outs() << "process cast " << SVFUtil::value2String(&inst) << " \n");
NodeID dst = getValueNode(&inst);

if (SVFUtil::isa<IntToPtrInst>(&inst))
if (IntToPtrInst *I2P = SVFUtil::dyn_cast<IntToPtrInst>(&inst))
{
// always use blk for IntToPtr
bool handleBlk = Options::HandBlackHole;
if (PointerType *PT = SVFUtil::dyn_cast<PointerType>(I2P->getDestTy())) {
bool isFptr = PT->getElementType()->isFunctionTy();
Options::HandBlackHole = isFptr;
}
addBlackHoleAddrEdge(dst);
Options::HandBlackHole = handleBlk;
}
else
{
Expand Down Expand Up @@ -1008,6 +1071,21 @@ const Value* SVFIRBuilder::getBaseValueForExtArg(const Value* V)
if(totalidx == 0 && !SVFUtil::isa<StructType>(value->getType()))
value = gep->getPointerOperand();
}

LLVMContext &cxt = LLVMModuleSet::getLLVMModuleSet()->getContext();
if (value->getType() == PointerType::getInt8PtrTy(cxt)) {
if (const CallBase* cb = SVFUtil::dyn_cast<CallBase>(value)) {
if (SVFUtil::isHeapAllocExtCallViaRet(cb)) {
if (const Value* bitCast = getUniqueUseViaCastInst(cb))
return bitCast;
}
}
else if (const LoadInst* load = SVFUtil::dyn_cast<LoadInst>(value)) {
if (const BitCastInst* bitCast = SVFUtil::dyn_cast<BitCastInst>(load->getPointerOperand()))
return bitCast->getOperand(0);
}
}

return value;
}

Expand All @@ -1019,6 +1097,7 @@ const Type *SVFIRBuilder::getBaseTypeAndFlattenedFields(const Value *V, std::vec
assert(V);
const Value* value = getBaseValueForExtArg(V);
const Type *T = value->getType();

while (const PointerType *ptype = SVFUtil::dyn_cast<PointerType>(T))
T = getPtrElementType(ptype);

Expand Down Expand Up @@ -1342,6 +1421,7 @@ void SVFIRBuilder::handleExtCall(CallSite cs, const SVFFunction *callee)
}
case ExtAPI::EXT_COMPLEX:
{
assert(cs.arg_size() == 4 && "_Rb_tree_insert_and_rebalance should have 4 arguments.\n");
Value *argA = cs.getArgument(getArgPos(args[0]));
Value *argB = cs.getArgument(getArgPos(args[1]));

Expand All @@ -1353,7 +1433,6 @@ void SVFIRBuilder::handleExtCall(CallSite cs, const SVFFunction *callee)
// We get all flattened fields of base
vector<LocationSet> fields;
const Type *type = getBaseTypeAndFlattenedFields(argB, fields, nullptr);
assert(fields.size() >= 4 && "_Rb_tree_node_base should have at least 4 fields.\n");

// We summarize the side effects: arg3->parent = arg1, arg3->left = arg1, arg3->right = arg1
// Note that arg0 is aligned with "offset".
Expand Down
6 changes: 3 additions & 3 deletions lib/Util/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const llvm::cl::opt<NodeIDAllocator::Strategy> Options::NodeAllocStrat(

const llvm::cl::opt<unsigned> Options::MaxFieldLimit(
"field-limit",
llvm::cl::init(512),
llvm::cl::init(51200),
llvm::cl::desc("Maximum number of fields for field sensitive analysis"));

const llvm::cl::opt<BVDataPTAImpl::PTBackingType> Options::ptDataBacking(
Expand Down Expand Up @@ -323,7 +323,7 @@ const llvm::cl::opt<bool> Options::PAGPrint(

const llvm::cl::opt<unsigned> Options::IndirectCallLimit(
"ind-call-limit",
llvm::cl::init(50000),
llvm::cl::init(5000000),
llvm::cl::desc("Indirect solved call edge limit")
);

Expand All @@ -347,7 +347,7 @@ const llvm::cl::opt<bool> Options::EnableThreadCallGraph(

const llvm::cl::opt<bool> Options::ConnectVCallOnCHA(
"v-call-cha",
llvm::cl::init(false),
llvm::cl::init(true),
llvm::cl::desc("connect virtual calls using cha")
);

Expand Down

0 comments on commit e5e23b1

Please sign in to comment.