Static Value-Flow Analysis
AccessPath.cpp
Go to the documentation of this file.
1 //===- AccessPath.cpp -- Location set for modeling abstract memory object----//
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  * @file: AccessPath.cpp
25  * @author: yesen
26  * @date: 26 Sep 2014
27  *
28  * LICENSE
29  *
30  */
31 
32 #include "Util/Options.h"
33 #include "MemoryModel/AccessPath.h"
34 #include "Util/SVFUtil.h"
35 
36 using namespace SVF;
37 using namespace SVFUtil;
38 
42 bool AccessPath::addOffsetVarAndGepTypePair(const SVFVar* var, const SVFType* gepIterType)
43 {
44  idxOperandPairs.emplace_back(var, gepIterType);
45  return true;
46 }
47 
50 {
51  for(auto it : idxOperandPairs)
52  {
53  if(SVFUtil::isa<SVFConstantInt>(it.first->getValue()) == false)
54  return false;
55  }
56  return true;
57 }
58 
64 {
65  if (SVFUtil::isa<SVFArrayType, SVFStructType>(type))
66  {
68  }
69  else if (type->isPointerTy())
70  {
71  // if type is a pointer, should be like:
72  // %2 = getelementptr inbounds i32*, i32** %1, ...
73  // where gepSrcPointee is of pointer type (i32*).
74  // this can be transformed to:
75  // %2 = getelementptr inbounds [N x i32], [N x i32]* %1, ...
76  // However, we do not know N without context information. int** implies non-contiguous blocks of memory
77  // In this case, we conservatively return max field limit
78  return Options::MaxFieldLimit();
79  }
80  else if (type->isSingleValueType() || SVFUtil::isa<SVFFunctionType>(type))
81  {
82  return 1;
83  }
84  else
85  {
86  SVFUtil::outs() << "GepIter Type" << *type << "\n";
87  assert(false && "What other types for this gep?");
88  abort();
89  }
90 }
91 
92 
95 // e.g. idxOperandVar: i32 2 idxOperandType: %struct.Student = type { i32, [i8 x 12], i32 }
96 // we accumulate field 0 (i32) byte size (4 Bytes), and field 1 ([i8x12]) byte size (12 Bytes)
97 // then the return byte offset is 16 Bytes.
98 u32_t AccessPath::getStructFieldOffset(const SVFVar* idxOperandVar, const SVFStructType* idxOperandType) const
99 {
100  const SVFValue* idxValue = idxOperandVar->getValue();
101  u32_t structByteOffset = 0;
102  if (const SVFConstantInt *op = SVFUtil::dyn_cast<SVFConstantInt>(idxValue))
103  {
104  for (u32_t structField = 0; structField < (u32_t) op->getSExtValue(); ++structField)
105  {
106  u32_t flattenIdx = idxOperandType->getTypeInfo()->getFlattenedFieldIdxVec()[structField];
107  structByteOffset += idxOperandType->getTypeInfo()->getOriginalElemType(flattenIdx)->getByteSize();
108  }
109  return structByteOffset;
110  }
111  else
112  {
113  assert(false && "struct type can only pair with constant idx");
114  abort();
115  }
116 }
117 
126 {
127  assert(isConstantOffset() && "not a constant offset");
128 
129  APOffset totalConstOffset = 0;
130  for(int i = idxOperandPairs.size() - 1; i >= 0; i--)
131  {
134  // (2) %arrayidx = getelementptr inbounds [10 x i8], [10 x i8]* %b, i64 0, i64 8
135  const SVFValue* value = idxOperandPairs[i].first->getValue();
142  const SVFType* type = idxOperandPairs[i].second;
146  assert(type && "this GepStmt comes from ExternalAPI cannot call this api");
147  const SVFType* type2 = type;
148  if (const SVFArrayType* arrType = SVFUtil::dyn_cast<SVFArrayType>(type))
149  {
151  type2 = arrType->getTypeOfElement();
152  }
153  else if (SVFUtil::isa<SVFPointerType>(type))
154  {
157  type2 = gepSrcPointeeType();
158  }
159 
160  const SVFConstantInt* op = SVFUtil::dyn_cast<SVFConstantInt>(value);
161  if (const SVFStructType* structType = SVFUtil::dyn_cast<SVFStructType>(type))
162  {
167  for (u32_t structField = 0; structField < (u32_t)op->getSExtValue(); ++structField)
168  {
169  u32_t flattenIdx = structType->getTypeInfo()->getFlattenedFieldIdxVec()[structField];
170  type2 = structType->getTypeInfo()->getOriginalElemType(flattenIdx);
171  totalConstOffset += type2->getByteSize();
172  }
173  }
174  else
175  {
178  totalConstOffset += op->getSExtValue() * type2->getByteSize();
179  }
180  }
181  totalConstOffset = Options::MaxFieldLimit() > totalConstOffset? totalConstOffset: Options::MaxFieldLimit();
182  return totalConstOffset;
183 }
184 
192 
194 // struct inner{ int rollNumber; float percentage;};
195 // struct Student { struct inner rollNumber; char studentName[10][3];}
196 // char x = studentRecord[1].studentName[3][2];
197 
214 {
215 
216  assert(isConstantOffset() && "not a constant offset");
217 
218  APOffset totalConstOffset = 0;
219  //After the model-const and model-array options are turned on,
220  // the gepstmt offset generated by the array on the global
221  // node will be saved in getConstantStructFldIdx
222  if (idxOperandPairs.size() == 0)
223  return getConstantStructFldIdx();
224  for(int i = idxOperandPairs.size() - 1; i >= 0; i--)
225  {
226  const SVFValue* value = idxOperandPairs[i].first->getValue();
227  const SVFType* type = idxOperandPairs[i].second;
228  const SVFConstantInt* op = SVFUtil::dyn_cast<SVFConstantInt>(value);
229  assert(op && "not a constant offset?");
230  if(type==nullptr)
231  {
232  totalConstOffset += op->getSExtValue();
233  continue;
234  }
235 
236  if(SVFUtil::isa<SVFPointerType>(type))
237  totalConstOffset += op->getSExtValue() * getElementNum(gepPointeeType);
238  else
239  {
240  APOffset offset = op->getSExtValue();
241  if (offset >= 0)
242  {
243  const std::vector<u32_t>& so = SymbolTableInfo::SymbolInfo()->getTypeInfo(type)->getFlattenedElemIdxVec();
244  // if offset is larger than the size of getFlattenedElemIdxVec (overflow)
245  // set offset the last index of getFlattenedElemIdxVec to avoid assertion
246  if (offset >= (APOffset)so.size())
247  {
248  SVFUtil::errs() << "It is an overflow access, hence it is the last idx\n";
249  offset = so.size() - 1;
250  }
251  else
252  {
253 
254  }
255 
256  u32_t flattenOffset =
258  offset);
259  totalConstOffset += flattenOffset;
260  }
261  }
262  }
263  return totalConstOffset;
264 }
269 {
270  NodeBS result;
271  result.set(getConstantStructFldIdx());
272  return result;
273 }
274 
276 {
277  assert(gepPointeeType == rhs.gepSrcPointeeType() && "source element type not match");
278  AccessPath ap(rhs);
279  ap.fldIdx += getConstantStructFldIdx();
280  for (auto &p : ap.getIdxOperandPairVec())
281  ap.addOffsetVarAndGepTypePair(p.first, p.second);
282 
283  return ap;
284 }
285 
286 bool AccessPath::operator< (const AccessPath& rhs) const
287 {
288  if (fldIdx != rhs.fldIdx)
289  return (fldIdx < rhs.fldIdx);
290  else
291  {
292  const IdxOperandPairs& pairVec = getIdxOperandPairVec();
293  const IdxOperandPairs& rhsPairVec = rhs.getIdxOperandPairVec();
294  if (pairVec.size() != rhsPairVec.size())
295  return (pairVec.size() < rhsPairVec.size());
296  else
297  {
298  IdxOperandPairs::const_iterator it = pairVec.begin();
299  IdxOperandPairs::const_iterator rhsIt = rhsPairVec.begin();
300  for (; it != pairVec.end() && rhsIt != rhsPairVec.end(); ++it, ++rhsIt)
301  {
302  return (*it) < (*rhsIt);
303  }
304 
305  return false;
306  }
307  }
308 }
309 
311 {
312  NodeBS lhsLocations = LHS.computeAllLocations();
313  NodeBS rhsLocations = RHS.computeAllLocations();
314  if (lhsLocations.intersects(rhsLocations))
315  {
316  if (lhsLocations == rhsLocations)
317  return Same;
318  else if (lhsLocations.contains(rhsLocations))
319  return Superset;
320  else if (rhsLocations.contains(lhsLocations))
321  return Subset;
322  else
323  return Overlap;
324  }
325  else
326  {
327  return NonOverlap;
328  }
329 }
330 
333 {
334  std::string str;
335  std::stringstream rawstr(str);
336 
337  rawstr << "AccessPath\tField_Index: " << getConstantStructFldIdx();
338  rawstr << ",\tNum-Stride: {";
339  const IdxOperandPairs& vec = getIdxOperandPairVec();
340  IdxOperandPairs::const_iterator it = vec.begin();
341  IdxOperandPairs::const_iterator eit = vec.end();
342  for (; it != eit; ++it)
343  {
344  const SVFType* ty = it->second;
345  rawstr << " (Svf var: " << it->first->toString() << ", Iter type: " << *ty << ")";
346  }
347  rawstr << " }\n";
348  return rawstr.str();
349 }
cJSON * p
Definition: cJSON.cpp:2559
newitem type
Definition: cJSON.cpp:2739
buffer offset
Definition: cJSON.cpp:1113
const char *const string
Definition: cJSON.h:172
std::vector< IdxOperandPair > IdxOperandPairs
Definition: AccessPath.h:65
u32_t getStructFieldOffset(const SVFVar *idxOperandVar, const SVFStructType *idxOperandType) const
Return byte offset from the beginning of the structure to the field where it is located for struct ty...
Definition: AccessPath.cpp:98
bool addOffsetVarAndGepTypePair(const SVFVar *var, const SVFType *gepIterType)
Definition: AccessPath.cpp:42
u32_t getElementNum(const SVFType *type) const
Return element number of a type.
Definition: AccessPath.cpp:63
bool isConstantOffset() const
Return TRUE if this is a constant location set.
Definition: AccessPath.cpp:49
APOffset computeConstantByteOffset() const
Definition: AccessPath.cpp:125
std::string dump() const
Dump location set.
Definition: AccessPath.cpp:332
const IdxOperandPairs & getIdxOperandPairVec() const
Definition: AccessPath.h:108
AccessPath operator+(const AccessPath &rhs) const
Overload operators.
Definition: AccessPath.cpp:275
NodeBS computeAllLocations() const
Compute all possible locations according to offset and number-stride pairs.
Definition: AccessPath.cpp:268
const SVFType * gepSrcPointeeType() const
Definition: AccessPath.h:112
LSRelation checkRelation(const AccessPath &LHS, const AccessPath &RHS)
Check relations of two location sets.
Definition: AccessPath.cpp:310
APOffset fldIdx
Accumulated Constant Offsets.
Definition: AccessPath.h:175
bool operator<(const AccessPath &rhs) const
Definition: AccessPath.cpp:286
APOffset computeConstantOffset() const
For example,.
Definition: AccessPath.cpp:213
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition: Options.h:38
s64_t getSExtValue() const
Definition: SVFValue.h:959
StInfo * getTypeInfo()
Definition: SVFType.h:230
std::string toString() const
u32_t getByteSize() const
Definition: SVFType.h:244
const SVFValue * getValue() const
Get/has methods of the components.
Definition: SVFVariables.h:83
bool intersects(const SparseBitVector< ElementSize > *RHS) const
void set(unsigned Idx)
bool contains(const SparseBitVector< ElementSize > &RHS) const
const SVFType * getOriginalElemType(u32_t fldIdx) const
Definition: SVFValue.cpp:20
std::vector< u32_t > & getFlattenedElemIdxVec()
Definition: SVFType.h:98
std::vector< u32_t > & getFlattenedFieldIdxVec()
Definition: SVFType.h:94
u32_t getFlattenedElemIdx(const SVFType *T, u32_t origId)
Flattened element idx of an array or struct by considering stride.
static SymbolTableInfo * SymbolInfo()
Singleton design here to make sure we only have one instance during any analysis.
const StInfo * getTypeInfo(const SVFType *T) const
Get struct info.
u32_t getNumOfFlattenElements(const SVFType *T)
Number of flattened elements of an array or struct.
std::ostream & errs()
Overwrite llvm::errs()
Definition: SVFUtil.h:56
std::ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:50
for isBitcode
Definition: BasicTypes.h:68
s64_t APOffset
Definition: GeneralType.h:60
unsigned u32_t
Definition: GeneralType.h:46