Static Value-Flow Analysis
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 
30 #include "SVF-LLVM/SVFIRBuilder.h"
31 #include "Util/SVFUtil.h"
34 
35 using namespace std;
36 using namespace SVF;
37 using namespace SVFUtil;
38 using namespace LLVMUtil;
39 
43 const Type* SVFIRBuilder::getBaseTypeAndFlattenedFields(const Value* V, std::vector<AccessPath> &fields, const Value* szValue)
44 {
45  assert(V);
46  const Value* value = getBaseValueForExtArg(V);
47  const Type *objType = LLVMModuleSet::getLLVMModuleSet()->getTypeInference()->inferObjType(value);
48  u32_t numOfElems = pag->getSymbolInfo()->getNumOfFlattenElements(LLVMModuleSet::getLLVMModuleSet()->getSVFType(objType));
50  if(szValue && SVFUtil::isa<ConstantInt>(szValue))
51  {
52  numOfElems = (numOfElems > SVFUtil::cast<ConstantInt>(szValue)->getSExtValue()) ? SVFUtil::cast<ConstantInt>(szValue)->getSExtValue() : numOfElems;
53  }
54 
55  LLVMContext& context = LLVMModuleSet::getLLVMModuleSet()->getContext();
56  for(u32_t ei = 0; ei < numOfElems; ei++)
57  {
58  AccessPath ls(ei);
59  // make a ConstantInt and create char for the content type due to byte-wise copy
60  const ConstantInt* offset = ConstantInt::get(context, llvm::APInt(32, ei));
61  const SVFValue* svfOffset = LLVMModuleSet::getLLVMModuleSet()->getSVFValue(offset);
62  if (!pag->getSymbolInfo()->hasValSym(svfOffset))
63  {
64  SymbolTableBuilder builder(pag->getSymbolInfo());
65  builder.collectSym(offset);
66  pag->addValNode(svfOffset, pag->getSymbolInfo()->getValSym(svfOffset), nullptr);
67  }
68  ls.addOffsetVarAndGepTypePair(getPAG()->getGNode(getPAG()->getValueNode(svfOffset)), nullptr);
69  fields.push_back(ls);
70  }
71  return objType;
72 }
73 
78 void SVFIRBuilder::addComplexConsForExt(Value *D, Value *S, const Value* szValue)
79 {
80  assert(D && S);
81  NodeID vnD= getValueNode(D), vnS= getValueNode(S);
82  if(!vnD || !vnS)
83  return;
84 
85  std::vector<AccessPath> fields;
86 
87  //Get the max possible size of the copy, unless it was provided.
88  std::vector<AccessPath> srcFields;
89  std::vector<AccessPath> dstFields;
90  const Type* stype = getBaseTypeAndFlattenedFields(S, srcFields, szValue);
91  const Type* dtype = getBaseTypeAndFlattenedFields(D, dstFields, szValue);
92  if(srcFields.size() > dstFields.size())
93  fields = dstFields;
94  else
95  fields = srcFields;
96 
98  u32_t sz = fields.size();
99 
100  if (fields.size() == 1 && (LLVMUtil::isConstDataOrAggData(D) || LLVMUtil::isConstDataOrAggData(S)))
101  {
102  NodeID dummy = pag->addDummyValNode();
103  addLoadEdge(vnD,dummy);
104  addStoreEdge(dummy,vnS);
105  return;
106  }
107 
108  //For each field (i), add (Ti = *S + i) and (*D + i = Ti).
109  for (u32_t index = 0; index < sz; index++)
110  {
111  LLVMModuleSet* llvmmodule = LLVMModuleSet::getLLVMModuleSet();
112  const SVFType* dElementType = pag->getSymbolInfo()->getFlatternedElemType(llvmmodule->getSVFType(dtype),
113  fields[index].getConstantStructFldIdx());
114  const SVFType* sElementType = pag->getSymbolInfo()->getFlatternedElemType(llvmmodule->getSVFType(stype),
115  fields[index].getConstantStructFldIdx());
116  NodeID dField = getGepValVar(D,fields[index],dElementType);
117  NodeID sField = getGepValVar(S,fields[index],sElementType);
118  NodeID dummy = pag->addDummyValNode();
119  addLoadEdge(sField,dummy);
120  addStoreEdge(dummy,dField);
121  }
122 }
123 
124 void SVFIRBuilder::handleExtCall(const CallBase* cs, const SVFFunction* svfCallee)
125 {
126  const SVFInstruction* svfInst = LLVMModuleSet::getLLVMModuleSet()->getSVFInstruction(cs);
127  const SVFCallInst* svfCall = SVFUtil::cast<SVFCallInst>(svfInst);
128  const CallICFGNode *callICFGNode = llvmModuleSet()->getCallICFGNode(cs);
129 
130  if (isHeapAllocExtCallViaRet(callICFGNode))
131  {
132  NodeID val = pag->getValueNode(svfInst);
133  NodeID obj = pag->getObjectNode(svfInst);
134  addAddrWithHeapSz(obj, val, cs);
135  }
136  else if (isHeapAllocExtCallViaArg(callICFGNode))
137  {
138  u32_t arg_pos = getHeapAllocHoldingArgPosition(svfCallee);
139  const SVFValue* arg = svfCall->getArgOperand(arg_pos);
140  if (arg->getType()->isPointerTy())
141  {
142  NodeID vnArg = pag->getValueNode(arg);
143  NodeID dummy = pag->addDummyValNode();
144  NodeID obj = pag->addDummyObjNode(arg->getType());
145  if (vnArg && dummy && obj)
146  {
147  addAddrWithHeapSz(obj, dummy, cs);
148  addStoreEdge(dummy, vnArg);
149  }
150  }
151  else
152  {
153  writeWrnMsg("Arg receiving new object must be pointer type");
154  }
155  }
156  else if (isMemcpyExtFun(svfCallee))
157  {
158  // Side-effects similar to void *memcpy(void *dest, const void * src, size_t n)
159  // which copies n characters from memory area 'src' to memory area 'dest'.
160  if(svfCallee->getName().find("iconv") != std::string::npos)
161  addComplexConsForExt(cs->getArgOperand(3), cs->getArgOperand(1), nullptr);
162  else if(svfCallee->getName().find("bcopy") != std::string::npos)
163  addComplexConsForExt(cs->getArgOperand(1), cs->getArgOperand(0), cs->getArgOperand(2));
164  if(svfCall->arg_size() == 3)
165  addComplexConsForExt(cs->getArgOperand(0), cs->getArgOperand(1), cs->getArgOperand(2));
166  else
167  addComplexConsForExt(cs->getArgOperand(0), cs->getArgOperand(1), nullptr);
168  if(SVFUtil::isa<PointerType>(cs->getType()))
169  addCopyEdge(getValueNode(cs->getArgOperand(0)), getValueNode(cs), CopyStmt::COPYVAL);
170  }
171  else if(isMemsetExtFun(svfCallee))
172  {
173  // Side-effects similar to memset(void *str, int c, size_t n)
174  // which copies the character c (an unsigned char) to the first n characters of the string pointed to, by the argument str
175  std::vector<AccessPath> dstFields;
176  const Type *dtype = getBaseTypeAndFlattenedFields(cs->getArgOperand(0), dstFields, cs->getArgOperand(2));
177  u32_t sz = dstFields.size();
178  //For each field (i), add store edge *(arg0 + i) = arg1
179  for (u32_t index = 0; index < sz; index++)
180  {
181  LLVMModuleSet* llvmmodule = LLVMModuleSet::getLLVMModuleSet();
182  const SVFType* dElementType = pag->getSymbolInfo()->getFlatternedElemType(llvmmodule->getSVFType(dtype),
183  dstFields[index].getConstantStructFldIdx());
184  NodeID dField = getGepValVar(cs->getArgOperand(0), dstFields[index], dElementType);
185  addStoreEdge(getValueNode(cs->getArgOperand(1)),dField);
186  }
187  if(SVFUtil::isa<PointerType>(cs->getType()))
188  addCopyEdge(getValueNode(cs->getArgOperand(0)), getValueNode(cs), CopyStmt::COPYVAL);
189  }
190  else if(svfCallee->getName().compare("dlsym") == 0)
191  {
192  /*
193  Side-effects of void* dlsym( void* handle, const char* funName),
194  Locate the function with the name "funName," then add a "copy" edge between the callsite and that function.
195  dlsym() example:
196  int main() {
197  // Open the shared library
198  void* handle = dlopen("./my_shared_library.so", RTLD_LAZY);
199  // Find the function address
200  void (*myFunctionPtr)() = (void (*)())dlsym(handle, "myFunction");
201  // Call the function
202  myFunctionPtr();
203  }
204  */
205  const Value* src = cs->getArgOperand(1);
206  if(const GetElementPtrInst* gep = SVFUtil::dyn_cast<GetElementPtrInst>(src))
207  src = stripConstantCasts(gep->getPointerOperand());
208 
209  auto getHookFn = [](const Value* src)->const Function*
210  {
211  if (!SVFUtil::isa<GlobalVariable>(src))
212  return nullptr;
213 
214  auto *glob = SVFUtil::cast<GlobalVariable>(src);
215  if (!glob->hasInitializer() || !SVFUtil::isa<ConstantDataArray>(glob->getInitializer()))
216  return nullptr;
217 
218  auto *constarray = SVFUtil::cast<ConstantDataArray>(glob->getInitializer());
219  return LLVMUtil::getProgFunction(constarray->getAsCString().str());
220  };
221 
222  if (const Function *fn = getHookFn(src))
223  {
224  NodeID srcNode = getValueNode(fn);
225  addCopyEdge(srcNode, getValueNode(cs), CopyStmt::COPYVAL);
226  }
227  }
228  else if(svfCallee->getName().find("_ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_") != std::string::npos)
229  {
230  // 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.
231  assert(svfCall->arg_size() == 4 && "_Rb_tree_insert_and_rebalance should have 4 arguments.\n");
232 
233  // We have vArg3 points to the entry of _Rb_tree_node_base { color; parent; left; right; }.
234  // Now we calculate the offset from base to vArg3
235  NodeID vnArg3 = pag->getValueNode(svfCall->getArgOperand(3));
236  APOffset offset =
237  getAccessPathFromBaseNode(vnArg3).getConstantStructFldIdx();
238 
239  // We get all flattened fields of base
240  vector<AccessPath> fields = pag->getTypeLocSetsMap(vnArg3).second;
241 
242  // We summarize the side effects: arg3->parent = arg1, arg3->left = arg1, arg3->right = arg1
243  // Note that arg0 is aligned with "offset".
244  for (APOffset i = offset + 1; i <= offset + 3; ++i)
245  {
246  if((u32_t)i >= fields.size())
247  break;
248  const SVFType* elementType = pag->getSymbolInfo()->getFlatternedElemType(pag->getTypeLocSetsMap(vnArg3).first,
249  fields[i].getConstantStructFldIdx());
250  NodeID vnD = getGepValVar(cs->getArgOperand(3), fields[i], elementType);
251  NodeID vnS = pag->getValueNode(svfCall->getArgOperand(1));
252  if(vnD && vnS)
253  addStoreEdge(vnS,vnD);
254  }
255  }
256 
257  if (isThreadForkCall(callICFGNode))
258  {
259  if (const SVFFunction* forkedFun = SVFUtil::dyn_cast<SVFFunction>(getForkedFun(callICFGNode)->getValue()))
260  {
261  forkedFun = forkedFun->getDefFunForMultipleModule();
262  const SVFVar* actualParm = getActualParmAtForkSite(callICFGNode);
265  assert((forkedFun->arg_size() <= 2) && "Size of formal parameter of start routine should be one");
266  if (forkedFun->arg_size() <= 2 && forkedFun->arg_size() >= 1)
267  {
268  const SVFArgument* formalParm = forkedFun->getArg(0);
270  if (actualParm->isPointer() && formalParm->getType()->isPointerTy())
271  {
272  FunEntryICFGNode *entry = pag->getICFG()->getFunEntryICFGNode(forkedFun);
273  addThreadForkEdge(actualParm->getId(), pag->getValueNode(formalParm), callICFGNode, entry);
274  }
275  }
276  }
277  else
278  {
283  }
287  }
288 
290 }
buffer offset
Definition: cJSON.cpp:1113
int index
Definition: cJSON.h:170
bool addOffsetVarAndGepTypePair(const SVFVar *var, const SVFType *gepIterType)
Definition: AccessPath.cpp:42
SVFType * getSVFType(const Type *T)
Get or create SVFType and typeinfo.
NodeID getId() const
Get ID.
Definition: GenericGraph.h:260
const SVFValue * getArgOperand(u32_t i) const
Definition: SVFValue.h:711
u32_t arg_size() const
Definition: SVFValue.h:703
bool isPointerTy() const
Definition: SVFType.h:249
virtual const SVFType * getType() const
Definition: SVFValue.h:256
const std::string & getName() const
Definition: SVFValue.h:243
virtual bool isPointer() const
Whether it is a pointer.
Definition: SVFVariables.h:106
void collectSym(const Value *val)
const Function * getProgFunction(const std::string &funName)
Get program entry function from module.
Definition: LLVMUtil.cpp:39
const Value * stripConstantCasts(const Value *val)
Strip off the constant casts.
Definition: LLVMUtil.cpp:220
bool isHeapAllocExtCallViaRet(const Instruction *inst)
Definition: LLVMUtil.cpp:618
bool isConstDataOrAggData(const Value *val)
Return true if the value refers to constant data, e.g., i32 0.
Definition: LLVMUtil.h:327
bool isHeapAllocExtCallViaArg(const Instruction *inst)
Definition: LLVMUtil.cpp:634
const SVFVar * getActualParmAtForkSite(const CallICFGNode *cs)
Return sole argument of the thread routine.
Definition: SVFUtil.h:435
bool isMemsetExtFun(const SVFFunction *fun)
Definition: SVFUtil.h:288
bool isMemcpyExtFun(const SVFFunction *fun)
Definition: SVFUtil.h:283
u32_t getHeapAllocHoldingArgPosition(const SVFFunction *fun)
Get the position of argument that holds an allocated heap object.
Definition: SVFUtil.h:309
const SVFVar * getForkedFun(const CallICFGNode *inst)
Return thread fork function.
Definition: SVFUtil.h:356
bool isThreadForkCall(const CallICFGNode *inst)
Definition: SVFUtil.h:387
void writeWrnMsg(const std::string &msg)
Writes a message run through wrnMsg.
Definition: SVFUtil.cpp:66
for isBitcode
Definition: BasicTypes.h:68
llvm::Type Type
Definition: BasicTypes.h:83
llvm::CallBase CallBase
Definition: BasicTypes.h:146
u32_t NodeID
Definition: GeneralType.h:55
s64_t APOffset
Definition: GeneralType.h:60
llvm::Function Function
Definition: BasicTypes.h:85
llvm::Value Value
LLVM Basic classes.
Definition: BasicTypes.h:82
llvm::GetElementPtrInst GetElementPtrInst
Definition: BasicTypes.h:162
unsigned u32_t
Definition: GeneralType.h:46
llvm::ConstantInt ConstantInt
Definition: BasicTypes.h:125
llvm::LLVMContext LLVMContext
Definition: BasicTypes.h:70