Static Value-Flow Analysis
Public Member Functions | List of all members
SVF::RelationSolver Class Reference

#include <RelationSolver.h>

Public Member Functions

 RelationSolver ()=default
 
Z3Expr gamma_hat (const AbstractState &exeState) const
 Return Z3Expr according to valToValMap. More...
 
Z3Expr gamma_hat (const AbstractState &alpha, const AbstractState &exeState) const
 Return Z3Expr according to another valToValMap. More...
 
Z3Expr gamma_hat (u32_t id, const AbstractState &exeState) const
 Return Z3Expr from a NodeID. More...
 
AbstractState abstract_consequence (const AbstractState &lower, const AbstractState &upper, const AbstractState &domain) const
 
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. More...
 
Z3Expr toIntVal (s32_t f) const
 
Z3Expr toRealVal (BoundedDouble f) const
 
AbstractState bilateral (const AbstractState &domain, const Z3Expr &phi, u32_t descend_check=0)
 
AbstractState RSY (const AbstractState &domain, const Z3Expr &phi)
 
Map< u32_t, s32_tBoxedOptSolver (const Z3Expr &phi, Map< u32_t, s32_t > &ret, Map< u32_t, s32_t > &low_values, Map< u32_t, s32_t > &high_values)
 
AbstractState BS (const AbstractState &domain, const Z3Expr &phi)
 
void updateMap (Map< u32_t, s32_t > &map, u32_t key, const s32_t &value)
 
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 > &)
 

Detailed Description

Definition at line 38 of file RelationSolver.h.

Constructor & Destructor Documentation

◆ RelationSolver()

SVF::RelationSolver::RelationSolver ( )
default

Member Function Documentation

◆ abstract_consequence()

AbstractState RelationSolver::abstract_consequence ( const AbstractState lower,
const AbstractState upper,
const AbstractState domain 
) const

for variable in self.variables:

proposed = self.top.copy()

proposed.set_interval(variable, lower.interval_of(variable)) proposed._locToItvVal

if not proposed >= upper:

return proposed

return lower.copy()

Definition at line 170 of file RelationSolver.cpp.

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 }
const VarToAbsValMap & getVarToVal() const
get var2val map
AbstractState top() const
Set all value top.

◆ beta()

AbstractState RelationSolver::beta ( const Map< u32_t, s32_t > &  sigma,
const AbstractState exeState 
) const

Definition at line 245 of file RelationSolver.cpp.

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 }
cJSON * item
Definition: cJSON.h:222

◆ bilateral()

AbstractState RelationSolver::bilateral ( const AbstractState domain,
const Z3Expr phi,
u32_t  descend_check = 0 
)

init variables

TODO: add option for timeout

start processing

compute domain.model_and(phi, domain.logic_not(domain.gamma_hat(consequence)))

find any solution, which is sat

unknown or unsat

for timeout reason return upper

Definition at line 36 of file RelationSolver.cpp.

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 }
unsigned u32_t
Definition: CommandLine.h:18
cJSON * p
Definition: cJSON.cpp:2559
AbstractState bottom() const
Set all value bottom.
void joinWith(const AbstractState &other)
domain join with other, important! other widen this.
void meetWith(const AbstractState &other)
domain meet with other, important! other widen this.
Z3Expr gamma_hat(const AbstractState &exeState) const
Return Z3Expr according to valToValMap.
AbstractState beta(const Map< u32_t, s32_t > &sigma, const AbstractState &exeState) const
AbstractState abstract_consequence(const AbstractState &lower, const AbstractState &upper, const AbstractState &domain) const
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
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition: GeneralType.h:101

◆ BoxedOptSolver()

Map< u32_t, s32_t > RelationSolver::BoxedOptSolver ( const Z3Expr phi,
Map< u32_t, s32_t > &  ret,
Map< u32_t, s32_t > &  low_values,
Map< u32_t, s32_t > &  high_values 
)

this is the S in the original paper

Definition at line 345 of file RelationSolver.cpp.

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 }
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)
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 > &)
Z3Expr toIntVal(s32_t f) const
signed s32_t
Definition: GeneralType.h:47

◆ BS()

AbstractState RelationSolver::BS ( const AbstractState domain,
const Z3Expr phi 
)

because key of _varToItvVal is u32_t, -key may out of range for int so we do key + bias for -key

init low, ret, high

init objects -x

add a relation that x == -(x+bias)

optimize each object

fill in the return values

Definition at line 270 of file RelationSolver.cpp.

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 }
virtual bool inVarToValTable(u32_t id) const
whether the variable is in varToVal table
static BoundedInt plus_infinity()
Definition: NumericValue.h:131
bool is_minus_infinity() const
Definition: NumericValue.h:107
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
const BoundedInt & lb() const
Return the lower bound.
const BoundedInt & ub() const
Return the upper bound.
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
Definition: IntervalValue.h:94
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)
Z3Expr simplify() const
Definition: Z3Expr.h:137

◆ decide_cpa_ext()

void RelationSolver::decide_cpa_ext ( const Z3Expr phi,
Map< u32_t, Z3Expr > &  L_phi,
Map< u32_t, s32_t > &  mid_values,
Map< u32_t, s32_t > &  ret,
Map< u32_t, s32_t > &  low_values,
Map< u32_t, s32_t > &  high_values 
)

find any solution, which is sat

id is the var id, value is the solution found for var_id add a relation to check if the solution meets phi_id

unknown or unsat, we consider unknown as unsat

Definition at line 373 of file RelationSolver.cpp.

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 }

◆ gamma_hat() [1/3]

Z3Expr RelationSolver::gamma_hat ( const AbstractState alpha,
const AbstractState exeState 
) const

Return Z3Expr according to another valToValMap.

Definition at line 216 of file RelationSolver.cpp.

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 }
s64_t getNumeral() const
Retrieves the numeral value of the BoundedInt object.
Definition: NumericValue.h:661
bool isTop() const
Definition: IntervalValue.h:66
bool isBottom() const
Definition: IntervalValue.h:71

◆ gamma_hat() [2/3]

Z3Expr RelationSolver::gamma_hat ( const AbstractState exeState) const

Return Z3Expr according to valToValMap.

Definition at line 199 of file RelationSolver.cpp.

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 }

◆ gamma_hat() [3/3]

Z3Expr RelationSolver::gamma_hat ( u32_t  id,
const AbstractState exeState 
) const

Return Z3Expr from a NodeID.

Definition at line 234 of file RelationSolver.cpp.

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 }

◆ RSY()

AbstractState RelationSolver::RSY ( const AbstractState domain,
const Z3Expr phi 
)

TODO: add option for timeout

find any solution, which is sat

unknown or unsat

for timeout reason return upper

Definition at line 114 of file RelationSolver.cpp.

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 }

◆ toIntVal()

Z3Expr SVF::RelationSolver::toIntVal ( s32_t  f) const
inline

Definition at line 66 of file RelationSolver.h.

67  {
68  return Z3Expr::getContext().int_val(f);
69  }

◆ toIntZ3Expr()

virtual Z3Expr SVF::RelationSolver::toIntZ3Expr ( u32_t  varId) const
inlinevirtual

Return Z3 expression lazily based on SVFVar ID.

Definition at line 61 of file RelationSolver.h.

62  {
63  return Z3Expr::getContext().int_const(std::to_string(varId).c_str());
64  }

◆ toRealVal()

Z3Expr SVF::RelationSolver::toRealVal ( BoundedDouble  f) const
inline

Definition at line 70 of file RelationSolver.h.

71  {
72  return Z3Expr::getContext().real_val(std::to_string(f.getFVal()).c_str());
73  }

◆ updateMap()

void RelationSolver::updateMap ( Map< u32_t, s32_t > &  map,
u32_t  key,
const s32_t value 
)

Definition at line 257 of file RelationSolver.cpp.

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 }

The documentation for this class was generated from the following files: