Static Value-Flow Analysis
Loading...
Searching...
No Matches
SVFIRExtAPI.cpp
Go to the documentation of this file.
1//===- SVFIRExtAPI.cpp -- External function IR of SVF ---------------------------------------------//
2//
3// SVF: Static Value-Flow Analysis
4//
5// Copyright (C) <2013-> <Yulei Sui>
6//
7
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU Affero General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Affero General Public License for more details.
17
18// You should have received a copy of the GNU Affero General Public License
19// along with this program. If not, see <http://www.gnu.org/licenses/>.
20//
21//===----------------------------------------------------------------------===//
22
23/*
24 * SVFIRExtAPI.cpp
25 *
26 * Created on: 18, 5, 2023
27 * Author: Shuangxiang Kan
28 */
29
31#include "Util/SVFUtil.h"
34#include "Graphs/CallGraph.h"
35#include "Util/ExtAPI.h"
36#include "Util/Options.h"
37
38using namespace std;
39using namespace SVF;
40using namespace SVFUtil;
41using namespace LLVMUtil;
42
43namespace
44{
45
46struct MemcpyField
47{
48 APOffset byteOffset;
49 AccessPath accessPath;
50 const SVFType* elementType;
51};
52
54{
55 const std::string prefix = "STORE_TOP:Arg";
56 const size_t start = annotation.find(prefix);
57 if (start == std::string::npos)
58 return false;
59
60 size_t idx = start + prefix.size();
61 if (idx >= annotation.size() || annotation[idx] < '0' || annotation[idx] > '9')
62 return false;
63
64 firstArg = 0;
65 do
66 {
67 firstArg = firstArg * 10 + static_cast<u32_t>(annotation[idx] - '0');
68 ++idx;
69 }
70 while (idx < annotation.size() && annotation[idx] >= '0' && annotation[idx] <= '9');
71
72 return idx < annotation.size() && annotation[idx] == '+';
73}
74
76{
77 const FunObjVar* extFun = callICFGNode->getCalledFunction();
78 if (extFun == nullptr)
79 return false;
80
81 for (const std::string& annotation :
82 ExtAPI::getExtAPI()->getExtFuncAnnotations(extFun))
83 {
84 u32_t firstArg = 0;
86 return true;
87 }
88 return false;
89}
90
92 const Type* llvmType,
93 const SVFType* svfType,
94 const DataLayout& dl,
95 IRGraph* pag,
96 std::vector<MemcpyField>& fields,
99{
100 if (llvmType == nullptr || svfType == nullptr)
101 return;
108 const u32_t maxFields = std::max(Options::MaxFieldLimit(), u32_t{1});
109 if (fields.size() >= maxFields)
110 return;
111
112 if (svfType->isPointerTy())
113 {
114 fields.push_back({baseByteOffset, AccessPath(baseFldIdx), svfType});
115 return;
116 }
117
118 if (const auto* structType = SVFUtil::dyn_cast<StructType>(llvmType))
119 {
120 const StructLayout* layout = dl.getStructLayout(const_cast<StructType*>(structType));
121 for (u32_t i = 0;
122 i < structType->getNumElements() && fields.size() < maxFields; ++i)
123 {
124 const Type* elemLLVMType = structType->getElementType(i);
126 if (elemSVFType == nullptr)
127 return;
128 APOffset elemByteOffset = baseByteOffset + static_cast<APOffset>(layout->getElementOffset(i));
131 }
132 return;
133 }
134
135 if (const auto* arrayType = SVFUtil::dyn_cast<ArrayType>(llvmType))
136 {
137 const Type* elemLLVMType = arrayType->getElementType();
139 if (elemSVFType == nullptr)
140 return;
141 const APOffset elemByteSize = static_cast<APOffset>(dl.getTypeAllocSize(const_cast<Type*>(elemLLVMType)));
142 for (u32_t i = 0;
143 i < arrayType->getNumElements() && fields.size() < maxFields; ++i)
144 {
148 }
149 }
150}
151
152std::vector<MemcpyField> getMemcpyFields(const Value* value, const Type* llvmType, const SVFType* svfType)
153{
154 std::vector<MemcpyField> fields;
156 auto* pag = PAG::getPAG();
157 const DataLayout& dl = mset->getMainLLVMModule()->getDataLayout();
158 collectMemcpyFields(llvmType, svfType, dl, pag, fields);
159 return fields;
160}
161
163{
164 if (const auto* allocaInst = llvm::dyn_cast_or_null<AllocaInst>(baseValue))
165 return allocaInst->getAllocatedType();
166
167 if (const auto* global = llvm::dyn_cast_or_null<GlobalVariable>(baseValue))
168 return global->getValueType();
169
170 return fallbackType;
171}
172
173}
174
178const Type* SVFIRBuilder::getBaseTypeAndFlattenedFields(const Value* V, std::vector<AccessPath> &fields, const Value* szValue)
179{
180 assert(V);
181 const Value* value = getBaseValueForExtArg(V);
185 if(szValue && SVFUtil::isa<ConstantInt>(szValue))
186 {
187 auto szIntVal = LLVMUtil::getIntegerValue(SVFUtil::cast<ConstantInt>(szValue));
188 numOfElems = (numOfElems > szIntVal.first) ? szIntVal.first : numOfElems;
189 }
196 numOfElems = std::min(numOfElems, std::max(Options::MaxFieldLimit(), u32_t{1}));
197
199 for(u32_t ei = 0; ei < numOfElems; ei++)
200 {
202 // make a ConstantInt and create char for the content type due to byte-wise copy
203 const ConstantInt* offset = ConstantInt::get(context, llvm::APInt(32, ei));
204 if (!llvmModuleSet()->hasValueNode(offset))
205 {
207 builder.collectSym(offset);
209 pag->addConstantIntValNode(id, LLVMUtil::getIntegerValue(offset), nullptr, llvmModuleSet()->getSVFType(offset->getType()));
211 pag->getGNode(id));
212 }
213 ls.addOffsetVarAndGepTypePair(getPAG()->getValVar(llvmModuleSet()->getValueNode(offset)), nullptr);
214 fields.push_back(ls);
215 }
216 return objType;
217}
218
224{
225 assert(D && S);
227 if(!vnD || !vnS)
228 return;
229
230 std::vector<AccessPath> fields;
231
232 //Get the max possible size of the copy, unless it was provided.
233 std::vector<AccessPath> srcFields;
234 std::vector<AccessPath> dstFields;
237 if(srcFields.size() > dstFields.size())
238 fields = dstFields;
239 else
240 fields = srcFields;
241
243 u32_t sz = fields.size();
244
245 if (fields.size() == 1 && (LLVMUtil::isConstDataOrAggData(D) || LLVMUtil::isConstDataOrAggData(S)))
246 {
250 return;
251 }
252
259 const bool hasRemappedGlobalBase =
260 (dstFieldBase != D && SVFUtil::isa<GlobalVariable>(dstFieldBase)) ||
261 (srcFieldBase != S && SVFUtil::isa<GlobalVariable>(srcFieldBase));
262 const bool useByteLayoutMemcpy =
265 {
268 std::vector<MemcpyField> dstMemcpyFields = getMemcpyFields(D, dstLayoutType, dstSVFType);
269 std::vector<MemcpyField> srcMemcpyFields = getMemcpyFields(S, srcLayoutType, srcSVFType);
270 if (!dstMemcpyFields.empty() && !srcMemcpyFields.empty())
271 {
272 std::unordered_map<APOffset, MemcpyField> srcFieldsByByteOffset;
273 for (const auto& field : srcMemcpyFields)
274 srcFieldsByByteOffset.emplace(field.byteOffset, field);
275
276 const DataLayout& dl = llvmModuleSet()->getMainLLVMModule()->getDataLayout();
277 APOffset copyBytes = std::min<APOffset>(
278 static_cast<APOffset>(dl.getTypeAllocSize(const_cast<Type*>(dstLayoutType))),
279 static_cast<APOffset>(dl.getTypeAllocSize(const_cast<Type*>(srcLayoutType))));
280 if (szValue && SVFUtil::isa<ConstantInt>(szValue))
281 {
282 auto szIntVal = LLVMUtil::getIntegerValue(SVFUtil::cast<ConstantInt>(szValue));
283 copyBytes = std::min(copyBytes, static_cast<APOffset>(szIntVal.first));
284 }
285
286 for (const auto& dstField : dstMemcpyFields)
287 {
288 if (dstField.byteOffset >= copyBytes)
289 continue;
290 auto it = srcFieldsByByteOffset.find(dstField.byteOffset);
291 if (it == srcFieldsByByteOffset.end())
292 continue;
293
294 NodeID dField = getGepValVar(dstFieldBase, dstField.accessPath, dstField.elementType);
295 NodeID sField = getGepValVar(srcFieldBase, it->second.accessPath, it->second.elementType);
299 }
300 return;
301 }
302 }
303
304 //For each field (i), add (Ti = *S + i) and (*D + i = Ti).
305 for (u32_t index = 0; index < sz; index++)
306 {
309 fields[index].getConstantStructFldIdx());
311 fields[index].getConstantStructFldIdx());
317 }
318}
319
321{
323 const FunObjVar* extFun = callICFGNode->getCalledFunction();
324 if (extFun)
325 {
326 for (const std::string& annotation :
328 {
329 u32_t firstArg = 0;
331 continue;
332 if (firstArg >= cs->arg_size())
333 continue;
334
335 for (u32_t argIdx = firstArg; argIdx < cs->arg_size(); ++argIdx)
336 storeTopArgs.insert(argIdx);
337 }
338 }
339
341 {
342 const Value* arg = cs->getArgOperand(argIdx);
343 if (!arg->getType()->isPointerTy())
344 continue;
345
346 const Type* storedType =
348 NodeID src = pag->getBlkPtr();
349 NodeID dst = getValueNode(arg);
351 dst = fieldZero;
352 if (src && dst)
353 addStoreEdge(src, dst);
354 }
355}
356
358{
360
362 {
364 }
366 {
370 }
372 {
374 Value* arg = cs->getArgOperand(arg_pos);
375 if (cs->getArgOperand(arg_pos)->getType()->isPointerTy())
376 {
379 NodeID obj = pag->addDummyObjNode(llvmModuleSet()->getSVFType(cs->getArgOperand(arg_pos)->getType()));
380 if (vnArg && dummy && obj)
381 {
384 }
385 }
386 else
387 {
388 writeWrnMsg("Arg receiving new object must be pointer type");
389 }
390 }
392 {
393 // Side-effects similar to void *memcpy(void *dest, const void * src, size_t n)
394 // which copies n characters from memory area 'src' to memory area 'dest'.
395 if(callee->getName().find("iconv") != std::string::npos)
396 addComplexConsForExt(cs->getArgOperand(3), cs->getArgOperand(1), nullptr);
397 else if(callee->getName().find("bcopy") != std::string::npos)
398 addComplexConsForExt(cs->getArgOperand(1), cs->getArgOperand(0), cs->getArgOperand(2));
399 if(cs->arg_size() == 3)
400 addComplexConsForExt(cs->getArgOperand(0), cs->getArgOperand(1), cs->getArgOperand(2));
401 else
402 addComplexConsForExt(cs->getArgOperand(0), cs->getArgOperand(1), nullptr);
403 if(SVFUtil::isa<PointerType>(cs->getType()))
404 addCopyEdge(getValueNode(cs->getArgOperand(0)), getValueNode(cs), CopyStmt::COPYVAL);
405 }
407 {
408 // Side-effects similar to memset(void *str, int c, size_t n)
409 // which copies the character c (an unsigned char) to the first n characters of the string pointed to, by the argument str
410 std::vector<AccessPath> dstFields;
411 const Type *dtype = getBaseTypeAndFlattenedFields(cs->getArgOperand(0), dstFields, cs->getArgOperand(2));
412 u32_t sz = dstFields.size();
413 //For each field (i), add store edge *(arg0 + i) = arg1
414 for (u32_t index = 0; index < sz; index++)
415 {
418 dstFields[index].getConstantStructFldIdx());
419 NodeID dField = getGepValVar(cs->getArgOperand(0), dstFields[index], dElementType);
420 addStoreEdge(getValueNode(cs->getArgOperand(1)),dField);
421 }
422 if(SVFUtil::isa<PointerType>(cs->getType()))
423 addCopyEdge(getValueNode(cs->getArgOperand(0)), getValueNode(cs), CopyStmt::COPYVAL);
424 }
425 else if(callee->getName().compare("dlsym") == 0)
426 {
427 /*
428 Side-effects of void* dlsym( void* handle, const char* funName),
429 Locate the function with the name "funName," then add a "copy" edge between the callsite and that function.
430 dlsym() example:
431 int main() {
432 // Open the shared library
433 void* handle = dlopen("./my_shared_library.so", RTLD_LAZY);
434 // Find the function address
435 void (*myFunctionPtr)() = (void (*)())dlsym(handle, "myFunction");
436 // Call the function
437 myFunctionPtr();
438 }
439 */
440 const Value* src = cs->getArgOperand(1);
441 if(const GetElementPtrInst* gep = SVFUtil::dyn_cast<GetElementPtrInst>(src))
442 src = stripConstantCasts(gep->getPointerOperand());
443
444 auto getHookFn = [](const Value* src)->const Function*
445 {
446 if (!SVFUtil::isa<GlobalVariable>(src))
447 return nullptr;
448
449 auto *glob = SVFUtil::cast<GlobalVariable>(src);
450 if (!glob->hasInitializer() || !SVFUtil::isa<ConstantDataArray>(glob->getInitializer()))
451 return nullptr;
452
453 auto *constarray = SVFUtil::cast<ConstantDataArray>(glob->getInitializer());
454 return LLVMUtil::getProgFunction(constarray->getAsCString().str());
455 };
456
457 if (const Function *fn = getHookFn(src))
458 {
461 }
462 }
463 else if(callee->getName().find("_ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_") != std::string::npos)
464 {
465 // The purpose of this function is to insert a new node into the red-black tree and then rebalance the tree to ensure that the red-black tree properties are maintained.
466 assert(cs->arg_size() == 4 && "_Rb_tree_insert_and_rebalance should have 4 arguments.\n");
467
468 // We have vArg3 points to the entry of _Rb_tree_node_base { color; parent; left; right; }.
469 // Now we calculate the offset from base to vArg3
470 NodeID vnArg3 = llvmModuleSet()->getValueNode(cs->getArgOperand(3));
473
474 // We get all flattened fields of base
476
477 // We summarize the side effects: arg3->parent = arg1, arg3->left = arg1, arg3->right = arg1
478 // Note that arg0 is aligned with "offset".
479 for (APOffset i = offset + 1; i <= offset + 3; ++i)
480 {
481 if((u32_t)i >= fields.size())
482 break;
483 const SVFType* elementType = pag->getFlatternedElemType(pag->getTypeLocSetsMap(vnArg3).first,
484 fields[i].getConstantStructFldIdx());
485 NodeID vnD = getGepValVar(cs->getArgOperand(3), fields[i], elementType);
486 NodeID vnS = llvmModuleSet()->getValueNode(cs->getArgOperand(1));
487 if(vnD && vnS)
489 }
490 }
491
493 {
495 if (const FunValVar* funcValVar = SVFUtil::dyn_cast<FunValVar>(valVar))
496 {
501 assert((forkedFun->arg_size() <= 2) && "Size of formal parameter of start routine should be one");
502 if (forkedFun->arg_size() <= 2 && forkedFun->arg_size() >= 1)
503 {
504 const ArgValVar* formalParm = forkedFun->getArg(0);
506 if (actualParm->isPointer() && formalParm->getType()->isPointerTy())
507 {
509 addThreadForkEdge(actualParm->getId(), formalParm->getId(), callICFGNode, entry);
510 }
511 }
512 }
513 else
514 {
519 }
523 }
524
526}
unsigned u32_t
Definition CommandLine.h:18
buffer offset
Definition cJSON.cpp:1113
int index
Definition cJSON.h:170
APOffset getConstantStructFldIdx() const
Get methods.
Definition AccessPath.h:102
Class representing a function argument variable in the SVFIR.
static ExtAPI * getExtAPI()
Definition ExtAPI.cpp:44
const std::vector< std::string > & getExtFuncAnnotations(const FunObjVar *fun)
Definition ExtAPI.cpp:275
virtual const FunObjVar * getFunction() const
Get containing function, or null for globals/constants.
const FunObjVar * getDefFunForMultipleModule() const
NodeType * getGNode(NodeID id) const
Get a node.
FunEntryICFGNode * getFunEntryICFGNode(const FunObjVar *fun)
Add a function entry node.
Definition ICFG.cpp:243
u32_t getFlattenedElemIdx(const SVFType *T, u32_t origId)
Flattened element idx of an array or struct by considering stride.
Definition IRGraph.cpp:148
u32_t getNumOfFlattenElements(const SVFType *T)
Definition IRGraph.cpp:173
NodeID getBlkPtr() const
Definition IRGraph.h:254
const SVFType * getFlatternedElemType(const SVFType *baseType, u32_t flatten_idx)
Return the type of a flattened element given a flattened index.
Definition IRGraph.cpp:127
const SVFType * getOriginalElemType(const SVFType *baseType, u32_t origId) const
Definition IRGraph.cpp:143
NodeID getValueNode(const Value *V)
Module * getMainLLVMModule() const
Definition LLVMModule.h:369
static LLVMModuleSet * getLLVMModuleSet()
Definition LLVMModule.h:133
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
Definition LLVMModule.h:384
ObjTypeInference * getTypeInference()
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.
Definition Options.h:34
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)
NodeID addConstantIntValNode(NodeID i, const std::pair< s64_t, u64_t > &intValue, const ICFGNode *icfgNode, const SVFType *type)
Definition SVFIR.h:691
ICFG * getICFG() const
Definition SVFIR.h:231
NodeID addDummyValNode()
Definition SVFIR.h:566
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:120
SVFTypeLocSetsPair & getTypeLocSetsMap(NodeID argId)
Given an arg NodeId, get its base SVFType* and all its field location sets.
Definition SVFIR.h:341
NodeID addDummyObjNode(const SVFType *type)
Definition SVFIR.h:570
const Function * getProgFunction(const std::string &funName)
Get program entry function from module.
Definition LLVMUtil.cpp:41
const Value * stripConstantCasts(const Value *val)
Strip off the constant casts.
Definition LLVMUtil.cpp:220
bool isHeapAllocExtCallViaRet(const Instruction *inst)
Definition LLVMUtil.cpp:649
bool isMemcpyExtFun(const Function *fun)
Definition LLVMUtil.cpp:390
std::pair< s64_t, u64_t > getIntegerValue(const ConstantInt *intValue)
Definition LLVMUtil.h:85
bool isConstDataOrAggData(const Value *val)
Return true if the value refers to constant data, e.g., i32 0.
Definition LLVMUtil.h:378
bool isHeapAllocExtCallViaArg(const Instruction *inst)
Definition LLVMUtil.cpp:664
bool isMemsetExtFun(const Function *fun)
Definition LLVMUtil.cpp:396
bool isObject(const Value *ref)
Return true if this value refers to a object.
Definition LLVMUtil.cpp:61
u32_t getHeapAllocHoldingArgPosition(const Function *fun)
Definition LLVMUtil.cpp:402
bool isThreadForkCall(const CallICFGNode *inst)
Definition SVFUtil.h:360
void writeWrnMsg(const std::string &msg)
Writes a message run through wrnMsg.
Definition SVFUtil.cpp:72
const ValVar * getActualParmAtForkSite(const CallICFGNode *cs)
Return sole argument of the thread routine.
Definition SVFUtil.h:408
const ValVar * getForkedFun(const CallICFGNode *inst)
Return thread fork function.
Definition SVFUtil.h:331
for isBitcode
Definition BasicTypes.h:70
llvm::DataLayout DataLayout
Definition BasicTypes.h:112
llvm::Type Type
Definition BasicTypes.h:87
llvm::CallBase CallBase
Definition BasicTypes.h:153
llvm::StructType StructType
LLVM types.
Definition BasicTypes.h:98
u32_t NodeID
Definition GeneralType.h:76
llvm::StructLayout StructLayout
Definition BasicTypes.h:109
s64_t APOffset
Definition GeneralType.h:80
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::GetElementPtrInst GetElementPtrInst
Definition BasicTypes.h:169
unsigned u32_t
Definition GeneralType.h:67
llvm::ConstantInt ConstantInt
Definition BasicTypes.h:129
llvm::LLVMContext LLVMContext
Definition BasicTypes.h:72