Static Value-Flow Analysis
Loading...
Searching...
No Matches
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
31#include "Util/SVFUtil.h"
32#include "Util/Options.h"
33
34using namespace SVF;
35using namespace SVFUtil;
36
38{
39 return *this == other;
40}
41
43{
44 size_t h = getVarToVal().size() * 2;
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{
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 {
169 assert(SVFUtil::isa<ObjVar>(PAG::getPAG()->getGNode(baseObj)) && "Fail to get the base object address!");
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
185 const MemObj* obj = objVar->getMemObj();
186
187 // Handle constant data, arrays, and structures
188 if (obj->isConstDataOrConstGlobal() || obj->isConstantArray() || obj->isConstantStruct())
189 {
190 if (const ConstantIntObjVar* consInt = SVFUtil::dyn_cast<ConstantIntObjVar>(objVar))
191 {
192 s64_t numeral = consInt->getSExtValue();
193 (*this)[varId] = IntervalValue(numeral, numeral);
194 }
195 else if (const ConstantFPObjVar* consFP = SVFUtil::dyn_cast<ConstantFPObjVar>(objVar))
196 {
197 (*this)[varId] = IntervalValue(consFP->getFPValue(), consFP->getFPValue());
198 }
199 else if (SVFUtil::isa<ConstantNullPtrObjVar>(objVar))
200 {
201 (*this)[varId] = IntervalValue(0, 0);
202 }
203 else if (SVFUtil::isa<GlobalObjVar>(objVar))
204 {
206 }
207 else if (obj->isConstantArray() || obj->isConstantStruct())
208 {
209 (*this)[varId] = IntervalValue::top();
210 }
211 else
212 {
213 (*this)[varId] = IntervalValue::top();
214 }
215 }
216 // Handle non-constant memory objects
217 else
218 {
220 }
221 return;
222}
223
224// getElementIndex
226{
227 // If the GEP statement has a constant offset, return it directly as the interval value
228 if (gep->isConstantOffset())
229 return IntervalValue((s64_t)gep->accumulateConstantOffset());
230
231 IntervalValue res(0);
232 // Iterate over the list of offset variable and type pairs in reverse order
233 for (int i = gep->getOffsetVarAndGepTypePairVec().size() - 1; i >= 0; i--)
234 {
235 AccessPath::IdxOperandPair IdxVarAndType = gep->getOffsetVarAndGepTypePairVec()[i];
236 const SVFVar* var = gep->getOffsetVarAndGepTypePairVec()[i].first;
237 const SVFType* type = IdxVarAndType.second;
238
239 // Variables to store the lower and upper bounds of the index value
240 s64_t idxLb;
241 s64_t idxUb;
242
243 // Determine the lower and upper bounds based on whether the value is a constant
244 if (const ConstantIntValVar* constInt = SVFUtil::dyn_cast<ConstantIntValVar>(var))
245 idxLb = idxUb = constInt->getSExtValue();
246 else
247 {
248 IntervalValue idxItv = (*this)[var->getId()].getInterval();
249 if (idxItv.isBottom())
250 idxLb = idxUb = 0;
251 else
252 {
254 idxUb = idxItv.ub().getIntNumeral();
255 }
256 }
257
258 // Adjust the bounds if the type is a pointer
259 if (SVFUtil::isa<SVFPointerType>(type))
260 {
261 u32_t elemNum = gep->getAccessPath().getElementNum(gep->getAccessPath().gepSrcPointeeType());
262 idxLb = (double)Options::MaxFieldLimit() / elemNum < idxLb ? Options::MaxFieldLimit() : idxLb * elemNum;
263 idxUb = (double)Options::MaxFieldLimit() / elemNum < idxUb ? Options::MaxFieldLimit() : idxUb * elemNum;
264 }
265 // Adjust the bounds for array or struct types using the symbol table info
266 else
267 {
269 {
270 const std::vector<u32_t>& so = SymbolTableInfo::SymbolInfo()->getTypeInfo(type)->getFlattenedElemIdxVec();
271 if (so.empty() || idxUb >= (APOffset)so.size() || idxLb < 0)
272 {
273 idxLb = idxUb = 0;
274 }
275 else
276 {
279 }
280 }
281 else
282 idxLb = idxUb = 0;
283 }
284
285 // Add the calculated interval to the result
286 res = res + IntervalValue(idxLb, idxUb);
287 }
288
289 // Ensure the result is within the bounds of [0, MaxFieldLimit]
291 if (res.isBottom())
292 {
293 res = IntervalValue(0);
294 }
295 return res;
296}
297// getByteOffset
299{
300 // If the GEP statement has a constant byte offset, return it directly as the interval value
301 if (gep->isConstantOffset())
302 return IntervalValue((s64_t)gep->accumulateConstantByteOffset());
303
304 IntervalValue res(0); // Initialize the result interval 'res' to 0.
305
306 // Loop through the offsetVarAndGepTypePairVec in reverse order.
307 for (int i = gep->getOffsetVarAndGepTypePairVec().size() - 1; i >= 0; i--)
308 {
309 const SVFVar* idxOperandVar = gep->getOffsetVarAndGepTypePairVec()[i].first;
310 const SVFType* idxOperandType = gep->getOffsetVarAndGepTypePairVec()[i].second;
311
312 // Calculate the byte offset for array or pointer types
313 if (SVFUtil::isa<SVFArrayType>(idxOperandType) || SVFUtil::isa<SVFPointerType>(idxOperandType))
314 {
316 if (const SVFArrayType* arrOperandType = SVFUtil::dyn_cast<SVFArrayType>(idxOperandType))
317 elemByteSize = arrOperandType->getTypeOfElement()->getByteSize();
318 else if (SVFUtil::isa<SVFPointerType>(idxOperandType))
319 elemByteSize = gep->getAccessPath().gepSrcPointeeType()->getByteSize();
320 else
321 assert(false && "idxOperandType must be ArrType or PtrType");
322
323 if (const ConstantIntValVar* op = SVFUtil::dyn_cast<ConstantIntValVar>(idxOperandVar))
324 {
325 // Calculate the lower bound (lb) of the interval value
326 s64_t lb = (double)Options::MaxFieldLimit() / elemByteSize >= op->getSExtValue()
327 ? op->getSExtValue() * elemByteSize
329 res = res + IntervalValue(lb, lb);
330 }
331 else
332 {
333 IntervalValue idxVal = (*this)[idxOperandVar->getId()].getInterval();
334
335 if (idxVal.isBottom())
336 res = res + IntervalValue(0, 0);
337 else
338 {
339 // Ensure the bounds are non-negative and within the field limit
340 s64_t ub = (idxVal.ub().getIntNumeral() < 0) ? 0
341 : (double)Options::MaxFieldLimit() / elemByteSize >= idxVal.ub().getIntNumeral()
342 ? elemByteSize * idxVal.ub().getIntNumeral()
344 s64_t lb = (idxVal.lb().getIntNumeral() < 0) ? 0
345 : (double)Options::MaxFieldLimit() / elemByteSize >= idxVal.lb().getIntNumeral()
346 ? elemByteSize * idxVal.lb().getIntNumeral()
348 res = res + IntervalValue(lb, ub);
349 }
350 }
351 }
352 // Process struct subtypes by calculating the byte offset from the beginning to the field of the struct
353 else if (const SVFStructType* structOperandType = SVFUtil::dyn_cast<SVFStructType>(idxOperandType))
354 {
355 res = res + IntervalValue(gep->getAccessPath().getStructFieldOffset(idxOperandVar, structOperandType));
356 }
357 else
358 {
359 assert(false && "gep type pair only support arr/ptr/struct");
360 }
361 }
362 return res; // Return the resulting byte offset as an IntervalValue.
363}
364
366{
367 AbstractValue res;
368 for (auto addr : (*this)[varId].getAddrs())
369 {
370 res.join_with(load(addr)); // q = *p
371 }
372 return res;
373}
374// storeValue
376{
377 for (auto addr : (*this)[varId].getAddrs())
378 {
379 store(addr, val); // *p = q
380 }
381}
382
384{
385 SVFUtil::outs() << "-----------Var and Value-----------\n";
386 u32_t fieldWidth = 20;
387 SVFUtil::outs().flags(std::ios::left);
388 std::vector<std::pair<u32_t, AbstractValue>> varToAbsValVec(_varToAbsVal.begin(), _varToAbsVal.end());
389 std::sort(varToAbsValVec.begin(), varToAbsValVec.end(), [](const auto &a, const auto &b)
390 {
391 return a.first < b.first;
392 });
393 for (const auto &item: varToAbsValVec)
394 {
395 SVFUtil::outs() << std::left << std::setw(fieldWidth) << ("Var" + std::to_string(item.first));
396 if (item.second.isInterval())
397 {
398 SVFUtil::outs() << " Value: " << item.second.getInterval().toString() << "\n";
399 }
400 else if (item.second.isAddr())
401 {
402 SVFUtil::outs() << " Value: {";
403 u32_t i = 0;
404 for (const auto& addr: item.second.getAddrs())
405 {
406 ++i;
407 if (i < item.second.getAddrs().size())
408 {
409 SVFUtil::outs() << "0x" << std::hex << addr << ", ";
410 }
411 else
412 {
413 SVFUtil::outs() << "0x" << std::hex << addr;
414 }
415 }
416 SVFUtil::outs() << "}\n";
417 }
418 else
419 {
420 SVFUtil::outs() << " Value: ⊥\n";
421 }
422 }
423
424 std::vector<std::pair<u32_t, AbstractValue>> addrToAbsValVec(_addrToAbsVal.begin(), _addrToAbsVal.end());
425 std::sort(addrToAbsValVec.begin(), addrToAbsValVec.end(), [](const auto &a, const auto &b)
426 {
427 return a.first < b.first;
428 });
429
430 for (const auto& item: addrToAbsValVec)
431 {
432 std::ostringstream oss;
433 oss << "0x" << std::hex << AbstractState::getVirtualMemAddress(item.first);
434 SVFUtil::outs() << std::left << std::setw(fieldWidth) << oss.str();
435 if (item.second.isInterval())
436 {
437 SVFUtil::outs() << " Value: " << item.second.getInterval().toString() << "\n";
438 }
439 else if (item.second.isAddr())
440 {
441 SVFUtil::outs() << " Value: {";
442 u32_t i = 0;
443 for (const auto& addr: item.second.getAddrs())
444 {
445 ++i;
446 if (i < item.second.getAddrs().size())
447 {
448 SVFUtil::outs() << "0x" << std::hex << addr << ", ";
449 }
450 else
451 {
452 SVFUtil::outs() << "0x" << std::hex << addr;
453 }
454 }
455 SVFUtil::outs() << "}\n";
456 }
457 else
458 {
459 SVFUtil::outs() << " Value: ⊥\n";
460 }
461 }
462 SVFUtil::outs() << "-----------------------------------------\n";
463}
464
466{
467 SVFIR* svfir = PAG::getPAG();
468 if (inVarToAddrsTable(id))
469 {
470 const AbstractValue& addrs = (*this)[id];
471 for (auto addr: addrs.getAddrs())
472 {
474 if (addr_id == 0) // nullptr has no memobj, skip
475 continue;
476 return SVFUtil::dyn_cast<ObjVar>(svfir->getGNode(addr_id))->getMemObj()->getType();
477 }
478 }
479 else
480 {
481 // do nothing if no record in addrs table.
482 }
483 return nullptr;
484}
485
487{
488 SVFIR* svfir = PAG::getPAG();
489 if (const ObjVar* objvar = SVFUtil::dyn_cast<ObjVar>(addr->getRHSVar()))
490 {
491 objvar->getType();
492 if (objvar->getMemObj()->isConstantByteSize())
493 {
494 u32_t sz = objvar->getMemObj()->getByteSizeOfObj();
495 return sz;
496 }
497
498 else
499 {
500 const std::vector<SVFValue*>& sizes = addr->getArrSize();
501 // Default element size is set to 1.
502 u32_t elementSize = 1;
503 u64_t res = elementSize;
504 for (const SVFValue* value: sizes)
505 {
506 if (!inVarToValTable(svfir->getValueNode(value)))
507 {
508 (*this)[svfir->getValueNode(value)] = IntervalValue(Options::MaxFieldLimit());
509 }
511 (*this)[svfir->getValueNode(value)].getInterval();
512 res = res * itv.ub().getIntNumeral() > Options::MaxFieldLimit()? Options::MaxFieldLimit(): res * itv.ub().getIntNumeral();
513 }
514 return (u32_t)res;
515 }
516 }
517 assert (false && "Addr rhs value is not ObjVar");
518 abort();
519}
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
const AddrToAbsValMap & getLocToVal() const
get loc2val map
u32_t getAllocaInstByteSize(const AddrStmt *addr)
const VarToAbsValMap & getVarToVal() const
get var2val map
void store(u32_t addr, const AbstractValue &val)
void printAbstractState() 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)
virtual AbstractValue & load(u32_t addr)
IntervalValue getByteOffset(const GepStmt *gep)
AbstractValue loadValue(NodeID varId)
bool inVarToAddrsTable(u32_t id) const
whether the variable is in varToAddrs table
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.
virtual bool inVarToValTable(u32_t id) const
whether the variable is in varToVal table
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()
std::pair< const SVFVar *, const SVFType * > IdxOperandPair
Definition AccessPath.h:64
s64_t getIntNumeral() const
NodeType * getGNode(NodeID id) const
Get a node.
NodeID getValueNode(const SVFValue *V)
Definition IRGraph.h:137
void meet_with(const IntervalValue &other)
Return a intersected IntervalValue.
const BoundedInt & ub() const
Return the upper bound.
bool isBottom() const
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
const BoundedInt & lb() const
Return the lower bound.
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
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:116
NodeID getGepObjVar(const MemObj *obj, const APOffset &ap)
Get a field SVFIR Object node according to base mem obj and offset.
Definition SVFIR.cpp:423
u32_t getByteSize() const
Definition SVFType.h:244
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
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74
unsigned u32_t
Definition GeneralType.h:46
signed long long s64_t
Definition GeneralType.h:49