Static Value-Flow Analysis
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 #include "AE/Core/RelationSolver.h"
30 #include <cmath>
31 #include "Util/Options.h"
32 
33 using namespace SVF;
34 using namespace SVFUtil;
35 
37  u32_t descend_check)
38 {
40  AbstractState upper = domain.top();
41  AbstractState lower = domain.bottom();
42  u32_t meets_in_a_row = 0;
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);
48  AbstractState consequence;
49 
51  while (lower != upper)
52  {
53  if (meets_in_a_row == descend_check)
54  {
55  consequence = lower;
56  }
57  else
58  {
59  consequence = abstract_consequence(lower, upper, domain);
60  }
62  Z3Expr rhs = !(gamma_hat(consequence, domain));
63  solver.push();
64  solver.add(phi.getExpr() && rhs.getExpr());
65  Map<u32_t, s32_t> solution;
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();
88  AbstractState newLower = domain.bottom();
89  newLower.joinWith(lower);
90  AbstractState rhs = beta(solution, domain);
91  newLower.joinWith(rhs);
92  lower = newLower;
93  meets_in_a_row = 0;
94  }
95  else
96  {
97  solver.pop();
98  if (checkRes == z3::unknown)
99  {
101  if (solver.reason_unknown() == "timeout")
102  return upper;
103  }
104  AbstractState newUpper = domain.top();
105  newUpper.meetWith(upper);
106  newUpper.meetWith(consequence);
107  upper = newUpper;
108  meets_in_a_row += 1;
109  }
110  }
111  return upper;
112 }
113 
115 {
116  AbstractState lower = domain.bottom();
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  {
124  Z3Expr rhs = !(gamma_hat(lower, domain));
125  solver.push();
126  solver.add(phi.getExpr() && rhs.getExpr());
127  Map<u32_t, s32_t> solution;
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();
150  AbstractState newLower = domain.bottom();
151  newLower.joinWith(lower);
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  {
187  AbstractState proposed = domain.top();
188  proposed[it->first] = lower[it->first].getInterval();
191  if (!(proposed >= upper))
192  {
193  return proposed;
194  }
195  }
196  return lower;
197 }
198 
200 {
201  Z3Expr res(Z3Expr::getContext().bool_val(true));
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 {
219  Z3Expr res(Z3Expr::getContext().bool_val(true));
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;
279  Map<u32_t, s32_t> ret;
280  Map<u32_t, s32_t> low_values, high_values;
281  Z3Expr new_phi = phi;
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())
288  updateMap(low_values, item.first, -infinity);
289  else
290  updateMap(low_values, item.first, interval.lb().getIntNumeral());
291  if (interval.ub().is_plus_infinity())
292  updateMap(high_values, item.first, 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())
305  updateMap(low_values, reverse_key, -infinity);
306  else
307  updateMap(low_values, reverse_key, -interval.ub().getIntNumeral());
308  if (interval.lb().is_minus_infinity())
309  updateMap(high_values, reverse_key, infinity);
310  else
311  updateMap(high_values, reverse_key, -interval.lb().getIntNumeral());
313  new_phi = (new_phi && (toIntZ3Expr(reverse_key) == -1 * toIntZ3Expr(item.first)));
314  }
316  BoxedOptSolver(new_phi.simplify(), ret, low_values, high_values);
318  AbstractState retInv;
319  for (const auto& item: ret)
320  {
321  if (item.first >= bias)
322  {
323  if (!retInv.inVarToValTable(item.first-bias))
324  retInv[item.first-bias] = IntervalValue::top();
325 
326  if (item.second == (infinity))
327  retInv[item.first - bias] = IntervalValue(BoundedInt::minus_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 {
348  Map<u32_t, Z3Expr> L_phi;
349  Map<u32_t, s32_t> mid_values;
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
367  decide_cpa_ext(phi, L_phi, mid_values, ret, low_values, high_values);
368  }
369  return ret;
370 }
371 
372 
374  Map<u32_t, Z3Expr>& L_phi,
375  Map<u32_t, s32_t>& mid_values,
376  Map<u32_t, s32_t>& ret,
377  Map<u32_t, s32_t>& low_values,
378  Map<u32_t, s32_t>& high_values)
379 {
380  while (1)
381  {
382  Z3Expr join_expr(Z3Expr::getContext().bool_val(false));
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());
389  Map<u32_t, double> solution;
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;
413  updateMap(mid_values, id, mid);
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.
const VarToAbsValMap & getVarToVal() const
get var2val map
virtual bool inVarToValTable(u32_t id) const
whether the variable is in varToVal table
AbstractState top() const
Set all value top.
void meetWith(const AbstractState &other)
domain meet with other, important! other widen this.
static BoundedInt plus_infinity()
Definition: NumericValue.h:131
bool is_minus_infinity() const
Definition: NumericValue.h:107
s64_t getNumeral() const
Retrieves the numeral value of the BoundedInt object.
Definition: NumericValue.h:661
bool is_plus_infinity() const
Definition: NumericValue.h:101
s64_t getIntNumeral() const
Definition: NumericValue.h:703
static BoundedInt minus_infinity()
Definition: NumericValue.h:137
bool isTop() const
Definition: IntervalValue.h:66
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
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
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)
static z3::solver & getSolver()
Get z3 solver, singleton design here to make sure we only have one context.
Definition: Z3Expr.cpp:56
const z3::expr & getExpr() const
Definition: Z3Expr.h:86
static z3::context & getContext()
Get z3 context, singleton design here to make sure we only have one context.
Definition: Z3Expr.cpp:66
Z3Expr simplify() const
Definition: Z3Expr.h:137
for isBitcode
Definition: BasicTypes.h:68
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition: GeneralType.h:101
signed s32_t
Definition: GeneralType.h:47
unsigned u32_t
Definition: GeneralType.h:46