Static Value-Flow Analysis
AbstractState.cpp
Go to the documentation of this file.
1 //===- IntervalExeState.cpp----Interval Domain-------------------------//
2 //
3 // SVF: Static Value-Flow Analysis
4 //
5 // Copyright (C) <2013-2022> <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  * AbstractExeState.cpp
24  *
25  * Created on: Jul 9, 2022
26  * Author: Xiao Cheng, Jiawei Wang
27  *
28  */
29 
30 #include "AE/Core/AbstractState.h"
31 #include "Util/SVFUtil.h"
32 #include "Util/Options.h"
33 
34 using namespace SVF;
35 using namespace SVFUtil;
36 
37 bool AbstractState::equals(const AbstractState&other) const
38 {
39  return *this == other;
40 }
41 
43 {
44  size_t h = getVarToVal().size() * 2;
45  Hash<u32_t> hf;
46  for (const auto &t: getVarToVal())
47  {
48  h ^= hf(t.first) + 0x9e3779b9 + (h << 6) + (h >> 2);
49  }
50  size_t h2 = getLocToVal().size() * 2;
51  for (const auto &t: getLocToVal())
52  {
53  h2 ^= hf(t.first) + 0x9e3779b9 + (h2 << 6) + (h2 >> 2);
54  }
56  return pairH({h, h2});
57 }
58 
60 {
61  // widen interval
62  AbstractState es = *this;
63  for (auto it = es._varToAbsVal.begin(); it != es._varToAbsVal.end(); ++it)
64  {
65  auto key = it->first;
66  if (other._varToAbsVal.find(key) != other._varToAbsVal.end())
67  if (it->second.isInterval() && other._varToAbsVal.at(key).isInterval())
68  it->second.getInterval().widen_with(other._varToAbsVal.at(key).getInterval());
69  }
70  for (auto it = es._addrToAbsVal.begin(); it != es._addrToAbsVal.end(); ++it)
71  {
72  auto key = it->first;
73  if (other._addrToAbsVal.find(key) != other._addrToAbsVal.end())
74  if (it->second.isInterval() && other._addrToAbsVal.at(key).isInterval())
75  it->second.getInterval().widen_with(other._addrToAbsVal.at(key).getInterval());
76  }
77  return es;
78 }
79 
81 {
82  AbstractState es = *this;
83  for (auto it = es._varToAbsVal.begin(); it != es._varToAbsVal.end(); ++it)
84  {
85  auto key = it->first;
86  if (other._varToAbsVal.find(key) != other._varToAbsVal.end())
87  if (it->second.isInterval() && other._varToAbsVal.at(key).isInterval())
88  it->second.getInterval().narrow_with(other._varToAbsVal.at(key).getInterval());
89  }
90  for (auto it = es._addrToAbsVal.begin(); it != es._addrToAbsVal.end(); ++it)
91  {
92  auto key = it->first;
93  if (other._addrToAbsVal.find(key) != other._addrToAbsVal.end())
94  if (it->second.isInterval() && other._addrToAbsVal.at(key).isInterval())
95  it->second.getInterval().narrow_with(other._addrToAbsVal.at(key).getInterval());
96  }
97  return es;
98 
99 }
100 
103 {
104  for (auto it = other._varToAbsVal.begin(); it != other._varToAbsVal.end(); ++it)
105  {
106  auto key = it->first;
107  auto oit = _varToAbsVal.find(key);
108  if (oit != _varToAbsVal.end())
109  {
110  oit->second.join_with(it->second);
111  }
112  else
113  {
114  _varToAbsVal.emplace(key, it->second);
115  }
116  }
117  for (auto it = other._addrToAbsVal.begin(); it != other._addrToAbsVal.end(); ++it)
118  {
119  auto key = it->first;
120  auto oit = _addrToAbsVal.find(key);
121  if (oit != _addrToAbsVal.end())
122  {
123  oit->second.join_with(it->second);
124  }
125  else
126  {
127  _addrToAbsVal.emplace(key, it->second);
128  }
129  }
130 }
131 
134 {
135  for (auto it = other._varToAbsVal.begin(); it != other._varToAbsVal.end(); ++it)
136  {
137  auto key = it->first;
138  auto oit = _varToAbsVal.find(key);
139  if (oit != _varToAbsVal.end())
140  {
141  oit->second.meet_with(it->second);
142  }
143  }
144  for (auto it = other._addrToAbsVal.begin(); it != other._addrToAbsVal.end(); ++it)
145  {
146  auto key = it->first;
147  auto oit = _addrToAbsVal.find(key);
148  if (oit != _addrToAbsVal.end())
149  {
150  oit->second.meet_with(it->second);
151  }
152  }
153 }
154 
155 // getGepObjAddrs
157 {
158  AddressValue gepAddrs;
159  APOffset lb = offset.lb().getIntNumeral() < Options::MaxFieldLimit() ? offset.lb().getIntNumeral()
161  APOffset ub = offset.ub().getIntNumeral() < Options::MaxFieldLimit() ? offset.ub().getIntNumeral()
163  for (APOffset i = lb; i <= ub; i++)
164  {
165  AbstractValue addrs = (*this)[pointer];
166  for (const auto& addr : addrs.getAddrs())
167  {
168  s64_t baseObj = AbstractState::getInternalID(addr);
169  assert(SVFUtil::isa<ObjVar>(PAG::getPAG()->getGNode(baseObj)) && "Fail to get the base object address!");
170  NodeID gepObj = PAG::getPAG()->getGepObjVar(baseObj, i);
171  (*this)[gepObj] = AddressValue(AbstractState::getVirtualMemAddress(gepObj));
173  }
174  }
175 
176  return gepAddrs;
177 }
178 // initObjVar
180 {
181  NodeID varId = objVar->getId();
182 
183  // Check if the object variable has an associated value
184  if (objVar->hasValue())
185  {
186  const MemObj* obj = objVar->getMemObj();
187 
188  // Handle constant data, arrays, and structures
189  if (obj->isConstDataOrConstGlobal() || obj->isConstantArray() || obj->isConstantStruct())
190  {
191  if (const SVFConstantInt* consInt = SVFUtil::dyn_cast<SVFConstantInt>(obj->getValue()))
192  {
193  s64_t numeral = consInt->getSExtValue();
194  (*this)[varId] = IntervalValue(numeral, numeral);
195  }
196  else if (const SVFConstantFP* consFP = SVFUtil::dyn_cast<SVFConstantFP>(obj->getValue()))
197  {
198  (*this)[varId] = IntervalValue(consFP->getFPValue(), consFP->getFPValue());
199  }
200  else if (SVFUtil::isa<SVFConstantNullPtr>(obj->getValue()))
201  {
202  (*this)[varId] = IntervalValue(0, 0);
203  }
204  else if (SVFUtil::isa<SVFGlobalValue>(obj->getValue()))
205  {
206  (*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId));
207  }
208  else if (obj->isConstantArray() || obj->isConstantStruct())
209  {
210  (*this)[varId] = IntervalValue::top();
211  }
212  else
213  {
214  (*this)[varId] = IntervalValue::top();
215  }
216  }
217  // Handle non-constant memory objects
218  else
219  {
220  (*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId));
221  }
222  }
223  // If the object variable does not have an associated value, set it to a virtual memory address
224  else
225  {
226  (*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId));
227  }
228  return;
229 }
230 
231 // getElementIndex
233 {
234  // If the GEP statement has a constant offset, return it directly as the interval value
235  if (gep->isConstantOffset())
237 
238  IntervalValue res(0);
239  // Iterate over the list of offset variable and type pairs in reverse order
240  for (int i = gep->getOffsetVarAndGepTypePairVec().size() - 1; i >= 0; i--)
241  {
243  const SVFValue* value = gep->getOffsetVarAndGepTypePairVec()[i].first->getValue();
244  const SVFType* type = IdxVarAndType.second;
245 
246  // Variables to store the lower and upper bounds of the index value
247  s64_t idxLb;
248  s64_t idxUb;
249 
250  // Determine the lower and upper bounds based on whether the value is a constant
251  if (const SVFConstantInt* constInt = SVFUtil::dyn_cast<SVFConstantInt>(value))
252  idxLb = idxUb = constInt->getSExtValue();
253  else
254  {
255  IntervalValue idxItv = (*this)[PAG::getPAG()->getValueNode(value)].getInterval();
256  if (idxItv.isBottom())
257  idxLb = idxUb = 0;
258  else
259  {
260  idxLb = idxItv.lb().getIntNumeral();
261  idxUb = idxItv.ub().getIntNumeral();
262  }
263  }
264 
265  // Adjust the bounds if the type is a pointer
266  if (SVFUtil::isa<SVFPointerType>(type))
267  {
269  idxLb = (double)Options::MaxFieldLimit() / elemNum < idxLb ? Options::MaxFieldLimit() : idxLb * elemNum;
270  idxUb = (double)Options::MaxFieldLimit() / elemNum < idxUb ? Options::MaxFieldLimit() : idxUb * elemNum;
271  }
272  // Adjust the bounds for array or struct types using the symbol table info
273  else
274  {
275  if (Options::ModelArrays())
276  {
277  const std::vector<u32_t>& so = SymbolTableInfo::SymbolInfo()->getTypeInfo(type)->getFlattenedElemIdxVec();
278  if (so.empty() || idxUb >= (APOffset)so.size() || idxLb < 0)
279  {
280  idxLb = idxUb = 0;
281  }
282  else
283  {
286  }
287  }
288  else
289  idxLb = idxUb = 0;
290  }
291 
292  // Add the calculated interval to the result
293  res = res + IntervalValue(idxLb, idxUb);
294  }
295 
296  // Ensure the result is within the bounds of [0, MaxFieldLimit]
298  if (res.isBottom())
299  {
300  res = IntervalValue(0);
301  }
302  return res;
303 }
304 // getByteOffset
306 {
307  // If the GEP statement has a constant byte offset, return it directly as the interval value
308  if (gep->isConstantOffset())
310 
311  IntervalValue res(0); // Initialize the result interval 'res' to 0.
312 
313  // Loop through the offsetVarAndGepTypePairVec in reverse order.
314  for (int i = gep->getOffsetVarAndGepTypePairVec().size() - 1; i >= 0; i--)
315  {
316  const SVFVar* idxOperandVar = gep->getOffsetVarAndGepTypePairVec()[i].first;
317  const SVFType* idxOperandType = gep->getOffsetVarAndGepTypePairVec()[i].second;
318 
319  // Calculate the byte offset for array or pointer types
320  if (SVFUtil::isa<SVFArrayType>(idxOperandType) || SVFUtil::isa<SVFPointerType>(idxOperandType))
321  {
322  u32_t elemByteSize = 1;
323  if (const SVFArrayType* arrOperandType = SVFUtil::dyn_cast<SVFArrayType>(idxOperandType))
324  elemByteSize = arrOperandType->getTypeOfElement()->getByteSize();
325  else if (SVFUtil::isa<SVFPointerType>(idxOperandType))
326  elemByteSize = gep->getAccessPath().gepSrcPointeeType()->getByteSize();
327  else
328  assert(false && "idxOperandType must be ArrType or PtrType");
329 
330  if (const SVFConstantInt* op = SVFUtil::dyn_cast<SVFConstantInt>(idxOperandVar->getValue()))
331  {
332  // Calculate the lower bound (lb) of the interval value
333  s64_t lb = (double)Options::MaxFieldLimit() / elemByteSize >= op->getSExtValue()
334  ? op->getSExtValue() * elemByteSize
336  res = res + IntervalValue(lb, lb);
337  }
338  else
339  {
340  u32_t idx = PAG::getPAG()->getValueNode(idxOperandVar->getValue());
341  IntervalValue idxVal = (*this)[idx].getInterval();
342 
343  if (idxVal.isBottom())
344  res = res + IntervalValue(0, 0);
345  else
346  {
347  // Ensure the bounds are non-negative and within the field limit
348  s64_t ub = (idxVal.ub().getIntNumeral() < 0) ? 0
349  : (double)Options::MaxFieldLimit() / elemByteSize >= idxVal.ub().getIntNumeral()
350  ? elemByteSize * idxVal.ub().getIntNumeral()
352  s64_t lb = (idxVal.lb().getIntNumeral() < 0) ? 0
353  : (double)Options::MaxFieldLimit() / elemByteSize >= idxVal.lb().getIntNumeral()
354  ? elemByteSize * idxVal.lb().getIntNumeral()
356  res = res + IntervalValue(lb, ub);
357  }
358  }
359  }
360  // Process struct subtypes by calculating the byte offset from the beginning to the field of the struct
361  else if (const SVFStructType* structOperandType = SVFUtil::dyn_cast<SVFStructType>(idxOperandType))
362  {
363  res = res + IntervalValue(gep->getAccessPath().getStructFieldOffset(idxOperandVar, structOperandType));
364  }
365  else
366  {
367  assert(false && "gep type pair only support arr/ptr/struct");
368  }
369  }
370  return res; // Return the resulting byte offset as an IntervalValue.
371 }
372 
374 {
375  AbstractValue res;
376  for (auto addr : (*this)[varId].getAddrs())
377  {
378  res.join_with(load(addr)); // q = *p
379  }
380  return res;
381 }
382 // storeValue
384 {
385  for (auto addr : (*this)[varId].getAddrs())
386  {
387  store(addr, val); // *p = q
388  }
389 }
390 
392 {
393  SVFUtil::outs() << "-----------Var and Value-----------\n";
394  u32_t fieldWidth = 20;
395  SVFUtil::outs().flags(std::ios::left);
396  std::vector<std::pair<u32_t, AbstractValue>> varToAbsValVec(_varToAbsVal.begin(), _varToAbsVal.end());
397  std::sort(varToAbsValVec.begin(), varToAbsValVec.end(), [](const auto &a, const auto &b)
398  {
399  return a.first < b.first;
400  });
401  for (const auto &item: varToAbsValVec)
402  {
403  SVFUtil::outs() << std::left << std::setw(fieldWidth) << ("Var" + std::to_string(item.first));
404  if (item.second.isInterval())
405  {
406  SVFUtil::outs() << " Value: " << item.second.getInterval().toString() << "\n";
407  }
408  else if (item.second.isAddr())
409  {
410  SVFUtil::outs() << " Value: {";
411  u32_t i = 0;
412  for (const auto& addr: item.second.getAddrs())
413  {
414  ++i;
415  if (i < item.second.getAddrs().size())
416  {
417  SVFUtil::outs() << "0x" << std::hex << addr << ", ";
418  }
419  else
420  {
421  SVFUtil::outs() << "0x" << std::hex << addr;
422  }
423  }
424  SVFUtil::outs() << "}\n";
425  }
426  else
427  {
428  SVFUtil::outs() << " Value: ⊥\n";
429  }
430  }
431 
432  std::vector<std::pair<u32_t, AbstractValue>> addrToAbsValVec(_addrToAbsVal.begin(), _addrToAbsVal.end());
433  std::sort(addrToAbsValVec.begin(), addrToAbsValVec.end(), [](const auto &a, const auto &b)
434  {
435  return a.first < b.first;
436  });
437 
438  for (const auto& item: addrToAbsValVec)
439  {
440  std::ostringstream oss;
441  oss << "0x" << std::hex << AbstractState::getVirtualMemAddress(item.first);
442  SVFUtil::outs() << std::left << std::setw(fieldWidth) << oss.str();
443  if (item.second.isInterval())
444  {
445  SVFUtil::outs() << " Value: " << item.second.getInterval().toString() << "\n";
446  }
447  else if (item.second.isAddr())
448  {
449  SVFUtil::outs() << " Value: {";
450  u32_t i = 0;
451  for (const auto& addr: item.second.getAddrs())
452  {
453  ++i;
454  if (i < item.second.getAddrs().size())
455  {
456  SVFUtil::outs() << "0x" << std::hex << addr << ", ";
457  }
458  else
459  {
460  SVFUtil::outs() << "0x" << std::hex << addr;
461  }
462  }
463  SVFUtil::outs() << "}\n";
464  }
465  else
466  {
467  SVFUtil::outs() << " Value: ⊥\n";
468  }
469  }
470  SVFUtil::outs() << "-----------------------------------------\n";
471 }
472 
474 {
475  SVFIR* svfir = PAG::getPAG();
476  if (inVarToAddrsTable(id))
477  {
478  const AbstractValue& addrs = (*this)[id];
479  for (auto addr: addrs.getAddrs())
480  {
481  NodeID addr_id = AbstractState::getInternalID(addr);
482  if (addr_id == 0) // nullptr has no memobj, skip
483  continue;
484  return SVFUtil::dyn_cast<ObjVar>(svfir->getGNode(addr_id))->getMemObj()->getType();
485  }
486  }
487  else
488  {
489  // do nothing if no record in addrs table.
490  }
491  return nullptr;
492 }
493 
495 {
496  SVFIR* svfir = PAG::getPAG();
497  if (const ObjVar* objvar = SVFUtil::dyn_cast<ObjVar>(addr->getRHSVar()))
498  {
499  objvar->getType();
500  if (objvar->getMemObj()->isConstantByteSize())
501  {
502  u32_t sz = objvar->getMemObj()->getByteSizeOfObj();
503  return sz;
504  }
505 
506  else
507  {
508  const std::vector<SVFValue*>& sizes = addr->getArrSize();
509  // Default element size is set to 1.
510  u32_t elementSize = 1;
511  u64_t res = elementSize;
512  for (const SVFValue* value: sizes)
513  {
514  if (!inVarToValTable(svfir->getValueNode(value)))
515  {
516  (*this)[svfir->getValueNode(value)] = IntervalValue(Options::MaxFieldLimit());
517  }
518  IntervalValue itv =
519  (*this)[svfir->getValueNode(value)].getInterval();
520  res = res * itv.ub().getIntNumeral() > Options::MaxFieldLimit()? Options::MaxFieldLimit(): res * itv.ub().getIntNumeral();
521  }
522  return (u32_t)res;
523  }
524  }
525  assert (false && "Addr rhs value is not ObjVar");
526  abort();
527 }
newitem type
Definition: cJSON.cpp:2739
cJSON * a
Definition: cJSON.cpp:2560
buffer offset
Definition: cJSON.cpp:1113
const cJSON *const b
Definition: cJSON.h:255
cJSON * item
Definition: cJSON.h:222
u32_t getAllocaInstByteSize(const AddrStmt *addr)
void printAbstractState() const
u32_t hash() const
void joinWith(const AbstractState &other)
domain join with other, important! other widen this.
IntervalValue getElementIndex(const GepStmt *gep)
bool equals(const AbstractState &other) const
VarToAbsValMap _varToAbsVal
Map a variable (symbol) to its abstract value.
AddrToAbsValMap _addrToAbsVal
Map a memory address to its stored abstract value.
const SVFType * getPointeeElement(NodeID id)
IntervalValue getByteOffset(const GepStmt *gep)
AbstractValue loadValue(NodeID varId)
static u32_t getVirtualMemAddress(u32_t idx)
The physical address starts with 0x7f...... + idx.
AbstractState narrowing(const AbstractState &other)
domain narrow with other, and return the narrowed domain
static u32_t getInternalID(u32_t idx)
Return the internal index if idx is an address otherwise return the value of idx.
void storeValue(NodeID varId, AbstractValue val)
void meetWith(const AbstractState &other)
domain meet with other, important! other widen this.
AddressValue getGepObjAddrs(u32_t pointer, IntervalValue offset)
void initObjVar(ObjVar *objVar)
AbstractState widening(const AbstractState &other)
domain widen with other, and return the widened domain
void join_with(const AbstractValue &other)
AddressValue & getAddrs()
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
u32_t getElementNum(const SVFType *type) const
Return element number of a type.
Definition: AccessPath.cpp:63
std::pair< const SVFVar *, const SVFType * > IdxOperandPair
Definition: AccessPath.h:64
const SVFType * gepSrcPointeeType() const
Definition: AccessPath.h:112
const std::vector< SVFValue * > & getArrSize() const
std::pair< AddressValue::AddrSet::iterator, bool > insert(u32_t id)
Definition: AddressValue.h:112
SVFVar * getRHSVar() const
s64_t getIntNumeral() const
Definition: NumericValue.h:703
NodeType * getGNode(NodeID id) const
Get a node.
Definition: GenericGraph.h:653
APOffset accumulateConstantOffset() const
Return accumulated constant offset (when accessing array or struct) if this offset is a constant.
APOffset accumulateConstantByteOffset() const
const AccessPath::IdxOperandPairs getOffsetVarAndGepTypePairVec() const
const AccessPath & getAccessPath() const
bool isConstantOffset() const
Return TRUE if this is a constant location set.
NodeID getValueNode(const SVFValue *V)
Definition: IRGraph.h:137
void meet_with(const IntervalValue &other)
Return a intersected IntervalValue.
const BoundedInt & lb() const
Return the lower bound.
bool isBottom() const
Definition: IntervalValue.h:71
const BoundedInt & ub() const
Return the upper bound.
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
Definition: IntervalValue.h:94
bool isConstantStruct() const
bool isConstDataOrConstGlobal() const
const SVFValue * getValue() const
Get the reference value to this object.
bool isConstantArray() const
const MemObj * getMemObj() const
Return memory object.
Definition: SVFVariables.h:358
static const Option< bool > ModelArrays
Definition: Options.h:188
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition: Options.h:38
NodeID getId() const
Get ID.
Definition: GenericGraph.h:260
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition: SVFIR.h:115
NodeID getGepObjVar(const MemObj *obj, const APOffset &ap)
Get a field SVFIR Object node according to base mem obj and offset.
Definition: SVFIR.cpp:422
u32_t getByteSize() const
Definition: SVFType.h:244
bool hasValue() const
Definition: SVFVariables.h:101
const SVFValue * getValue() const
Get/has methods of the components.
Definition: SVFVariables.h:83
std::vector< u32_t > & getFlattenedElemIdxVec()
Definition: SVFType.h:98
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.
std::ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:50
for isBitcode
Definition: BasicTypes.h:68
unsigned long long u64_t
Definition: GeneralType.h:48
u32_t NodeID
Definition: GeneralType.h:55
s64_t APOffset
Definition: GeneralType.h:60
unsigned u32_t
Definition: GeneralType.h:46
signed long long s64_t
Definition: GeneralType.h:49
provide extra hash function for std::pair handling
Definition: GeneralType.h:85