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 */
30#include <cmath>
31#include "Util/Options.h"
32
33using namespace SVF;
34using namespace SVFUtil;
35
38{
43 z3::solver solver = Z3Expr::getSolver();
44 z3::params p(Z3Expr::getContext());
46 p.set(":timeout", static_cast<unsigned>(600)); // in milliseconds
47 solver.set(p);
49
51 while (lower != upper)
52 {
54 {
56 }
57 else
58 {
60 }
63 solver.push();
64 solver.add(phi.getExpr() && rhs.getExpr());
66 z3::check_result checkRes = solver.check();
68 if (checkRes == z3::sat)
69 {
70 z3::model m = solver.get_model();
71 for (u32_t i = 0; i < m.size(); i++)
72 {
73 z3::func_decl v = m[i];
74 // assert(v.arity() == 0);
75 if (v.arity() != 0)
76 continue;
77 solution.emplace(std::stoi(v.name().str()),
78 m.get_const_interp(v).get_numeral_int());
79 }
80 for (const auto& item : domain.getVarToVal())
81 {
82 if (solution.find(item.first) == solution.end())
83 {
84 solution.emplace(item.first, 0);
85 }
86 }
87 solver.pop();
91 newLower.joinWith(rhs);
94 }
95 else
96 {
97 solver.pop();
98 if (checkRes == z3::unknown)
99 {
101 if (solver.reason_unknown() == "timeout")
102 return upper;
103 }
106 newUpper.meetWith(consequence);
107 upper = newUpper;
108 meets_in_a_row += 1;
109 }
110 }
111 return upper;
112}
113
115{
117 z3::solver& solver = Z3Expr::getSolver();
118 z3::params p(Z3Expr::getContext());
120 p.set(":timeout", static_cast<unsigned>(600)); // in milliseconds
121 solver.set(p);
122 while (1)
123 {
125 solver.push();
126 solver.add(phi.getExpr() && rhs.getExpr());
128 z3::check_result checkRes = solver.check();
130 if (checkRes == z3::sat)
131 {
132 z3::model m = solver.get_model();
133 for (u32_t i = 0; i < m.size(); i++)
134 {
135 z3::func_decl v = m[i];
136 if (v.arity() != 0)
137 continue;
138
139 solution.emplace(std::stoi(v.name().str()),
140 m.get_const_interp(v).get_numeral_int());
141 }
142 for (const auto& item : domain.getVarToVal())
143 {
144 if (solution.find(item.first) == solution.end())
145 {
146 solution.emplace(item.first, 0);
147 }
148 }
149 solver.pop();
152 newLower.joinWith(beta(solution, domain));
153 lower = newLower;
154 }
155 else
156 {
157 solver.pop();
158 if (checkRes == z3::unknown)
159 {
161 if (solver.reason_unknown() == "timeout")
162 return domain.top();
163 }
164 break;
165 }
166 }
167 return lower;
168}
169
171 const AbstractState& lower, const AbstractState& upper, const AbstractState& domain) const
172{
173 /*Returns the "abstract consequence" of lower and upper.
174
175 The abstract consequence must be a superset of lower and *NOT* a
176 superset of upper.
177
178 Note that this is a fairly "simple" abstract consequence, in that it
179 sets only one variable to a non-top interval. This improves performance
180 of the SMT solver in many cases. In certain cases, other choices for
181 the abstract consequence will lead to better algorithm performance.*/
182
183 for (auto it = domain.getVarToVal().begin();
184 it != domain.getVarToVal().end(); ++it)
186 {
188 proposed[it->first] = lower[it->first].getInterval();
191 if (!(proposed >= upper))
192 {
193 return proposed;
194 }
195 }
196 return lower;
197}
198
200{
202 for (auto& item : exeState.getVarToVal())
203 {
204 IntervalValue interval = item.second.getInterval();
205 if (interval.isBottom())
206 return Z3Expr::getContext().bool_val(false);
207 if (interval.isTop())
208 continue;
209 Z3Expr v = toIntZ3Expr(item.first);
210 res = (res && v >= (int)interval.lb().getNumeral() &&
211 v <= (int)interval.ub().getNumeral()).simplify();
212 }
213 return res;
214}
215
217 const AbstractState& exeState) const
218{
220 for (auto& item : exeState.getVarToVal())
221 {
222 IntervalValue interval = alpha[item.first].getInterval();
223 if (interval.isBottom())
224 return Z3Expr::getContext().bool_val(false);
225 if (interval.isTop())
226 continue;
227 Z3Expr v = toIntZ3Expr(item.first);
228 res = (res && v >= (int)interval.lb().getNumeral() &&
229 v <= (int)interval.ub().getNumeral()).simplify();
230 }
231 return res;
232}
233
235{
236 auto it = exeState.getVarToVal().find(id);
237 assert(it != exeState.getVarToVal().end() && "id not in varToVal?");
238 Z3Expr v = toIntZ3Expr(id);
239 // Z3Expr v = Z3Expr::getContext().int_const(std::to_string(id).c_str());
240 Z3Expr res = (v >= (int)it->second.getInterval().lb().getNumeral() &&
241 v <= (int)it->second.getInterval().ub().getNumeral());
242 return res;
243}
244
246 const AbstractState& exeState) const
247{
248 AbstractState res;
249 for (const auto& item : exeState.getVarToVal())
250 {
251 res[item.first] = IntervalValue(
252 sigma.at(item.first), sigma.at(item.first));
253 }
254 return res;
255}
256
258{
259 auto it = map.find(key);
260 if (it == map.end())
261 {
262 map.emplace(key, value);
263 }
264 else
265 {
266 it->second = value;
267 }
268}
269
271{
274 u32_t bias = 0;
275 s32_t infinity = INT32_MAX/2 - 1;
276
277 // int infinity = (INT32_MAX) - 1;
278 // int infinity = 20;
283 for (const auto& item: domain.getVarToVal())
284 {
285 IntervalValue interval = item.second.getInterval();
286 updateMap(ret, item.first, interval.ub().getIntNumeral());
287 if (interval.lb().is_minus_infinity())
289 else
290 updateMap(low_values, item.first, interval.lb().getIntNumeral());
291 if (interval.ub().is_plus_infinity())
293 else
294 updateMap(high_values, item.first, interval.ub().getIntNumeral());
295 if (item.first > bias)
296 bias = item.first + 1;
297 }
298 for (const auto& item: domain.getVarToVal())
299 {
301 IntervalValue interval = item.second.getInterval();
302 u32_t reverse_key = item.first + bias;
303 updateMap(ret, reverse_key, -interval.lb().getIntNumeral());
304 if (interval.ub().is_plus_infinity())
306 else
308 if (interval.lb().is_minus_infinity())
310 else
313 new_phi = (new_phi && (toIntZ3Expr(reverse_key) == -1 * toIntZ3Expr(item.first)));
314 }
316 BoxedOptSolver(new_phi.simplify(), ret, low_values, high_values);
319 for (const auto& item: ret)
320 {
321 if (item.first >= bias)
322 {
323 if (!retInv.inVarToValTable(item.first-bias))
325
326 if (item.second == (infinity))
328 retInv[item.first - bias].getInterval().ub());
329 else
330 retInv[item.first - bias] = IntervalValue(float(-item.second), retInv[item.first - bias].getInterval().ub());
331
332 }
333 else
334 {
335 if (item.second == (infinity))
336 retInv[item.first] = IntervalValue(retInv[item.first].getInterval().lb(),
338 else
339 retInv[item.first] = IntervalValue(retInv[item.first].getInterval().lb(), float(item.second));
340 }
341 }
342 return retInv;
343}
344
346{
350 while (1)
351 {
352 L_phi.clear();
353 for (const auto& item : ret)
354 {
355 Z3Expr v = toIntZ3Expr(item.first);
356 if (low_values.at(item.first) <= (high_values.at(item.first)))
357 {
358 s32_t mid = (low_values.at(item.first) + (high_values.at(item.first) - low_values.at(item.first)) / 2);
359 updateMap(mid_values, item.first, mid);
360 Z3Expr expr = (toIntVal(mid) <= v && v <= toIntVal(high_values.at(item.first)));
361 L_phi[item.first] = expr;
362 }
363 }
364 if (L_phi.empty())
365 break;
366 else
368 }
369 return ret;
370}
371
372
379{
380 while (1)
381 {
383 for (const auto& item : L_phi)
384 join_expr = (join_expr || item.second);
385 join_expr = (join_expr && phi).simplify();
386 z3::solver& solver = Z3Expr::getSolver();
387 solver.push();
388 solver.add(join_expr.getExpr());
390 z3::check_result checkRes = solver.check();
392 if (checkRes == z3::sat)
393 {
394 z3::model m = solver.get_model();
395 solver.pop();
396 for(const auto & item : L_phi)
397 {
398 u32_t id = item.first;
399 int value = m.eval(toIntZ3Expr(id).getExpr()).get_numeral_int();
400 // int value = m.eval(Z3Expr::getContext().int_const(std::to_string(id).c_str())).get_numeral_int();
403 Z3Expr expr = (item.second && toIntZ3Expr(id) == value);
404 solver.push();
405 solver.add(expr.getExpr());
406 // solution meets phi_id
407 if (solver.check() == z3::sat)
408 {
409 updateMap(ret, id, (value));
410 updateMap(low_values, id, ret.at(id) + 1);
411
412 s32_t mid = (low_values.at(id) + high_values.at(id) + 1) / 2;
414 Z3Expr v = toIntZ3Expr(id);
415 // Z3Expr v = Z3Expr::getContext().int_const(std::to_string(id).c_str());
416 Z3Expr expr = (toIntVal(mid_values.at(id)) <= v && v <= toIntVal(high_values.at(id)));
417 L_phi[id] = expr;
418 }
419 solver.pop();
420 }
421 }
422 else
423 {
424 solver.pop();
425 for (const auto& item : L_phi)
426 high_values.at(item.first) = mid_values.at(item.first) - 1;
427 return;
428 }
429 }
430
431}
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:68
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74
signed s32_t
Definition GeneralType.h:47
unsigned u32_t
Definition GeneralType.h:46