Static Value-Flow Analysis
Loading...
Searching...
No Matches
RelationSolver.cpp
Go to the documentation of this file.
1//===- RelationSolver.cpp ----Relation Solver for Interval Domains-----------//
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 * RelationSolver.cpp
24 *
25 * Created on: Aug 4, 2022
26 * Author: Jiawei Ren
27 *
28 */
29
30#include <cmath>
31
35#include "Util/GeneralType.h"
36#include "Util/Options.h"
37#include "Util/SVFUtil.h"
38
39using namespace SVF;
40using namespace SVFUtil;
41
44{
49 z3::solver solver = Z3Expr::getSolver();
50 z3::params p(Z3Expr::getContext());
52 p.set(":timeout", static_cast<unsigned>(600)); // in milliseconds
53 solver.set(p);
55
57 while (lower != upper)
58 {
60 {
62 }
63 else
64 {
66 }
69 solver.push();
70 solver.add(phi.getExpr() && rhs.getExpr());
72 z3::check_result checkRes = solver.check();
74 if (checkRes == z3::sat)
75 {
76 z3::model m = solver.get_model();
77 for (u32_t i = 0; i < m.size(); i++)
78 {
79 z3::func_decl v = m[i];
80 // assert(v.arity() == 0);
81 if (v.arity() != 0)
82 continue;
83 solution.emplace(std::stoi(v.name().str()),
84 m.get_const_interp(v).get_numeral_int());
85 }
86 for (const auto& item : domain.getVarToVal())
87 {
88 if (solution.find(item.first) == solution.end())
89 {
90 solution.emplace(item.first, 0);
91 }
92 }
93 solver.pop();
97 newLower.joinWith(rhs);
100 }
101 else
102 {
103 solver.pop();
104 if (checkRes == z3::unknown)
105 {
107 if (solver.reason_unknown() == "timeout")
108 return upper;
109 }
112 newUpper.meetWith(consequence);
113 upper = newUpper;
114 meets_in_a_row += 1;
115 }
116 }
117 return upper;
118}
119
121{
123 z3::solver& solver = Z3Expr::getSolver();
124 z3::params p(Z3Expr::getContext());
126 p.set(":timeout", static_cast<unsigned>(600)); // in milliseconds
127 solver.set(p);
128 while (1)
129 {
131 solver.push();
132 solver.add(phi.getExpr() && rhs.getExpr());
134 z3::check_result checkRes = solver.check();
136 if (checkRes == z3::sat)
137 {
138 z3::model m = solver.get_model();
139 for (u32_t i = 0; i < m.size(); i++)
140 {
141 z3::func_decl v = m[i];
142 if (v.arity() != 0)
143 continue;
144
145 solution.emplace(std::stoi(v.name().str()),
146 m.get_const_interp(v).get_numeral_int());
147 }
148 for (const auto& item : domain.getVarToVal())
149 {
150 if (solution.find(item.first) == solution.end())
151 {
152 solution.emplace(item.first, 0);
153 }
154 }
155 solver.pop();
158 newLower.joinWith(beta(solution, domain));
159 lower = newLower;
160 }
161 else
162 {
163 solver.pop();
164 if (checkRes == z3::unknown)
165 {
167 if (solver.reason_unknown() == "timeout")
168 return domain.top();
169 }
170 break;
171 }
172 }
173 return lower;
174}
175
177 const AbstractState& lower, const AbstractState& upper, const AbstractState& domain) const
178{
179 /*Returns the "abstract consequence" of lower and upper.
180
181 The abstract consequence must be a superset of lower and *NOT* a
182 superset of upper.
183
184 Note that this is a fairly "simple" abstract consequence, in that it
185 sets only one variable to a non-top interval. This improves performance
186 of the SMT solver in many cases. In certain cases, other choices for
187 the abstract consequence will lead to better algorithm performance.*/
188
189 for (auto it = domain.getVarToVal().begin();
190 it != domain.getVarToVal().end(); ++it)
192 {
194 proposed[it->first] = lower[it->first].getInterval();
197 if (!(proposed >= upper))
198 {
199 return proposed;
200 }
201 }
202 return lower;
203}
204
206{
208 for (auto& item : exeState.getVarToVal())
209 {
210 IntervalValue interval = item.second.getInterval();
211 if (interval.isBottom())
212 return Z3Expr::getContext().bool_val(false);
213 if (interval.isTop())
214 continue;
215 Z3Expr v = toIntZ3Expr(item.first);
216 res = (res && v >= (int)interval.lb().getNumeral() &&
217 v <= (int)interval.ub().getNumeral()).simplify();
218 }
219 return res;
220}
221
223 const AbstractState& exeState) const
224{
226 for (auto& item : exeState.getVarToVal())
227 {
228 IntervalValue interval = alpha[item.first].getInterval();
229 if (interval.isBottom())
230 return Z3Expr::getContext().bool_val(false);
231 if (interval.isTop())
232 continue;
233 Z3Expr v = toIntZ3Expr(item.first);
234 res = (res && v >= (int)interval.lb().getNumeral() &&
235 v <= (int)interval.ub().getNumeral()).simplify();
236 }
237 return res;
238}
239
241{
242 auto it = exeState.getVarToVal().find(id);
243 assert(it != exeState.getVarToVal().end() && "id not in varToVal?");
244 Z3Expr v = toIntZ3Expr(id);
245 // Z3Expr v = Z3Expr::getContext().int_const(std::to_string(id).c_str());
246 Z3Expr res = (v >= (int)it->second.getInterval().lb().getNumeral() &&
247 v <= (int)it->second.getInterval().ub().getNumeral());
248 return res;
249}
250
252 const AbstractState& exeState) const
253{
254 AbstractState res;
255 for (const auto& item : exeState.getVarToVal())
256 {
257 res[item.first] = IntervalValue(
258 sigma.at(item.first), sigma.at(item.first));
259 }
260 return res;
261}
262
264{
265 auto it = map.find(key);
266 if (it == map.end())
267 {
268 map.emplace(key, value);
269 }
270 else
271 {
272 it->second = value;
273 }
274}
275
277{
280 u32_t bias = 0;
281 s32_t infinity = INT32_MAX/2 - 1;
282
283 // int infinity = (INT32_MAX) - 1;
284 // int infinity = 20;
289 for (const auto& item: domain.getVarToVal())
290 {
291 IntervalValue interval = item.second.getInterval();
292 updateMap(ret, item.first, interval.ub().getIntNumeral());
293 if (interval.lb().is_minus_infinity())
295 else
296 updateMap(low_values, item.first, interval.lb().getIntNumeral());
297 if (interval.ub().is_plus_infinity())
299 else
300 updateMap(high_values, item.first, interval.ub().getIntNumeral());
301 if (item.first > bias)
302 bias = item.first + 1;
303 }
304 for (const auto& item: domain.getVarToVal())
305 {
307 IntervalValue interval = item.second.getInterval();
308 u32_t reverse_key = item.first + bias;
309 updateMap(ret, reverse_key, -interval.lb().getIntNumeral());
310 if (interval.ub().is_plus_infinity())
312 else
314 if (interval.lb().is_minus_infinity())
316 else
319 new_phi = (new_phi && (toIntZ3Expr(reverse_key) == -1 * toIntZ3Expr(item.first)));
320 }
322 BoxedOptSolver(new_phi.simplify(), ret, low_values, high_values);
325 for (const auto& item: ret)
326 {
327 if (item.first >= bias)
328 {
329 if (!retInv.inVarToValTable(item.first-bias))
331
332 if (item.second == (infinity))
334 retInv[item.first - bias].getInterval().ub());
335 else
336 retInv[item.first - bias] = IntervalValue(float(-item.second), retInv[item.first - bias].getInterval().ub());
337
338 }
339 else
340 {
341 if (item.second == (infinity))
342 retInv[item.first] = IntervalValue(retInv[item.first].getInterval().lb(),
344 else
345 retInv[item.first] = IntervalValue(retInv[item.first].getInterval().lb(), float(item.second));
346 }
347 }
348 return retInv;
349}
350
352{
356 while (1)
357 {
358 L_phi.clear();
359 for (const auto& item : ret)
360 {
361 Z3Expr v = toIntZ3Expr(item.first);
362 if (low_values.at(item.first) <= (high_values.at(item.first)))
363 {
364 s32_t mid = (low_values.at(item.first) + (high_values.at(item.first) - low_values.at(item.first)) / 2);
365 updateMap(mid_values, item.first, mid);
366 Z3Expr expr = (toIntVal(mid) <= v && v <= toIntVal(high_values.at(item.first)));
367 L_phi[item.first] = expr;
368 }
369 }
370 if (L_phi.empty())
371 break;
372 else
374 }
375 return ret;
376}
377
378
385{
386 while (1)
387 {
389 for (const auto& item : L_phi)
390 join_expr = (join_expr || item.second);
391 join_expr = (join_expr && phi).simplify();
392 z3::solver& solver = Z3Expr::getSolver();
393 solver.push();
394 solver.add(join_expr.getExpr());
396 z3::check_result checkRes = solver.check();
398 if (checkRes == z3::sat)
399 {
400 z3::model m = solver.get_model();
401 solver.pop();
402 for(const auto & item : L_phi)
403 {
404 u32_t id = item.first;
405 int value = m.eval(toIntZ3Expr(id).getExpr()).get_numeral_int();
406 // int value = m.eval(Z3Expr::getContext().int_const(std::to_string(id).c_str())).get_numeral_int();
409 Z3Expr expr = (item.second && toIntZ3Expr(id) == value);
410 solver.push();
411 solver.add(expr.getExpr());
412 // solution meets phi_id
413 if (solver.check() == z3::sat)
414 {
415 updateMap(ret, id, (value));
416 updateMap(low_values, id, ret.at(id) + 1);
417
418 s32_t mid = (low_values.at(id) + high_values.at(id) + 1) / 2;
420 Z3Expr v = toIntZ3Expr(id);
421 // Z3Expr v = Z3Expr::getContext().int_const(std::to_string(id).c_str());
422 Z3Expr expr = (toIntVal(mid_values.at(id)) <= v && v <= toIntVal(high_values.at(id)));
423 L_phi[id] = expr;
424 }
425 solver.pop();
426 }
427 }
428 else
429 {
430 solver.pop();
431 for (const auto& item : L_phi)
432 high_values.at(item.first) = mid_values.at(item.first) - 1;
433 return;
434 }
435 }
436
437}
cJSON * p
Definition cJSON.cpp:2559
cJSON * item
Definition cJSON.h:222
AbstractState bottom() const
Set all value bottom.
void joinWith(const AbstractState &other)
domain join with other, important! other widen this.
AbstractState top() const
Set all value top.
void meetWith(const AbstractState &other)
domain meet with other, important! other widen this.
static BoundedInt plus_infinity()
bool is_minus_infinity() const
s64_t getNumeral() const
Retrieves the numeral value of the BoundedInt object.
bool is_plus_infinity() const
s64_t getIntNumeral() const
static BoundedInt minus_infinity()
bool isTop() const
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.
Z3Expr gamma_hat(const AbstractState &exeState) const
Return Z3Expr according to valToValMap.
AbstractState RSY(const AbstractState &domain, const Z3Expr &phi)
AbstractState bilateral(const AbstractState &domain, const Z3Expr &phi, u32_t descend_check=0)
Map< u32_t, s32_t > BoxedOptSolver(const Z3Expr &phi, Map< u32_t, s32_t > &ret, Map< u32_t, s32_t > &low_values, Map< u32_t, s32_t > &high_values)
AbstractState beta(const Map< u32_t, s32_t > &sigma, const AbstractState &exeState) const
virtual Z3Expr toIntZ3Expr(u32_t varId) const
Return Z3 expression lazily based on SVFVar ID.
void updateMap(Map< u32_t, s32_t > &map, u32_t key, const s32_t &value)
AbstractState abstract_consequence(const AbstractState &lower, const AbstractState &upper, const AbstractState &domain) const
void decide_cpa_ext(const Z3Expr &phi, Map< u32_t, Z3Expr > &, Map< u32_t, s32_t > &, Map< u32_t, s32_t > &, Map< u32_t, s32_t > &, Map< u32_t, s32_t > &)
AbstractState BS(const AbstractState &domain, const Z3Expr &phi)
Z3Expr toIntVal(s32_t f) const
const z3::expr & getExpr() const
Definition Z3Expr.h:86
static z3::solver & getSolver()
Get z3 solver, singleton design here to make sure we only have one context.
Definition Z3Expr.cpp:56
static z3::context & getContext()
Get z3 context, singleton design here to make sure we only have one context.
Definition Z3Expr.cpp:66
for isBitcode
Definition BasicTypes.h:70
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
signed s32_t
Definition GeneralType.h:68
unsigned u32_t
Definition GeneralType.h:67