CBMC
invariant_set.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Invariant Set
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "invariant_set.h"
13 
14 #include <util/arith_tools.h>
15 #include <util/byte_operators.h>
16 #include <util/expr_util.h>
17 #include <util/namespace.h>
18 #include <util/pointer_expr.h>
19 #include <util/simplify_expr.h>
20 #include <util/std_code_base.h>
21 
22 #include <langapi/language_util.h>
23 
24 #include <iostream>
25 
26 void inv_object_storet::output(std::ostream &out) const
27 {
28  for(std::size_t i=0; i<entries.size(); i++)
29  out << "STORE " << i << ": " << map[i] << '\n';
30 }
31 
32 bool inv_object_storet::get(const exprt &expr, unsigned &n)
33 {
34  std::string s=build_string(expr);
35  if(s.empty())
36  return true;
37 
38  // if it's a constant, we add it in any case
39  if(is_constant(expr))
40  {
41  n=map.number(s);
42 
43  if(n>=entries.size())
44  {
45  entries.resize(n+1);
46  entries[n].expr=expr;
47  entries[n].is_constant=true;
48  }
49 
50  return false;
51  }
52 
53  if(const auto number = map.get_number(s))
54  {
55  n = *number;
56  return false;
57  }
58  return true;
59 }
60 
61 unsigned inv_object_storet::add(const exprt &expr)
62 {
63  std::string s=build_string(expr);
64  CHECK_RETURN(!s.empty());
65 
67 
68  if(n>=entries.size())
69  {
70  entries.resize(n+1);
71  entries[n].expr=expr;
72  entries[n].is_constant=is_constant(expr);
73  }
74 
75  return n;
76 }
77 
78 bool inv_object_storet::is_constant(unsigned n) const
79 {
80  PRECONDITION(n < entries.size());
81  return entries[n].is_constant;
82 }
83 
84 bool inv_object_storet::is_constant(const exprt &expr) const
85 {
86  return expr.is_constant() ||
87  is_constant_address(expr);
88 }
89 
90 std::string inv_object_storet::build_string(const exprt &expr) const
91 {
92  // we ignore some casts
93  if(expr.id()==ID_typecast)
94  {
95  const auto &typecast_expr = to_typecast_expr(expr);
96 
97  if(
98  typecast_expr.type().id() == ID_signedbv ||
99  typecast_expr.type().id() == ID_unsignedbv)
100  {
101  const typet &op_type = typecast_expr.op().type();
102 
103  if(op_type.id() == ID_signedbv || op_type.id() == ID_unsignedbv)
104  {
105  if(
106  to_bitvector_type(typecast_expr.type()).get_width() >=
107  to_bitvector_type(op_type).get_width())
108  {
109  return build_string(typecast_expr.op());
110  }
111  }
112  else if(op_type.id() == ID_bool)
113  {
114  return build_string(typecast_expr.op());
115  }
116  }
117  }
118 
119  // we always track constants, but make sure they are uniquely
120  // represented
121  if(expr.is_constant())
122  {
123  // NULL?
125  return "0";
126 
127  const auto i = numeric_cast<mp_integer>(expr);
128  if(i.has_value())
129  return integer2string(*i);
130  }
131 
132  // we also like "address_of" if the object is constant
133  // we don't know what mode (language) we are in, so we rely on the default
134  // language to be reasonable for from_expr
135  if(is_constant_address(expr))
136  return from_expr(ns, irep_idt(), expr);
137 
138  if(expr.id()==ID_member)
139  {
140  return build_string(to_member_expr(expr).compound()) + "." +
141  expr.get_string(ID_component_name);
142  }
143 
144  if(expr.id()==ID_symbol)
145  return id2string(to_symbol_expr(expr).get_identifier());
146 
147  return "";
148 }
149 
151  const exprt &expr,
152  unsigned &n) const
153 {
154  return object_store.get(expr, n);
155 }
156 
158 {
159  if(expr.id()==ID_address_of)
160  return is_constant_address_rec(to_address_of_expr(expr).object());
161 
162  return false;
163 }
164 
166 {
167  if(expr.id()==ID_symbol)
168  return true;
169  else if(expr.id()==ID_member)
170  return is_constant_address_rec(to_member_expr(expr).compound());
171  else if(expr.id()==ID_index)
172  {
173  const auto &index_expr = to_index_expr(expr);
174  if(index_expr.index().is_constant())
175  return is_constant_address_rec(index_expr.array());
176  }
177 
178  return false;
179 }
180 
182  const std::pair<unsigned, unsigned> &p,
183  ineq_sett &dest)
184 {
185  eq_set.check_index(p.first);
186  eq_set.check_index(p.second);
187 
188  // add all. Quadratic.
189  unsigned f_r=eq_set.find(p.first);
190  unsigned s_r=eq_set.find(p.second);
191 
192  for(std::size_t f=0; f<eq_set.size(); f++)
193  {
194  if(eq_set.find(f)==f_r)
195  {
196  for(std::size_t s=0; s<eq_set.size(); s++)
197  if(eq_set.find(s)==s_r)
198  dest.insert(std::pair<unsigned, unsigned>(f, s));
199  }
200  }
201 }
202 
203 void invariant_sett::add_eq(const std::pair<unsigned, unsigned> &p)
204 {
205  eq_set.make_union(p.first, p.second);
206 
207  // check if there is a contradiction with two constants
208  unsigned r=eq_set.find(p.first);
209 
210  bool constant_seen=false;
211  mp_integer c;
212 
213  for(std::size_t i=0; i<eq_set.size(); i++)
214  {
215  if(eq_set.find(i)==r)
216  {
218  {
219  if(constant_seen)
220  {
221  // contradiction
222  make_false();
223  return;
224  }
225  else
226  constant_seen=true;
227  }
228  }
229  }
230 
231  // replicate <= and != constraints
232 
233  for(const auto &le : le_set)
234  add_eq(le_set, p, le);
235 
236  for(const auto &ne : ne_set)
237  add_eq(ne_set, p, ne);
238 }
239 
241  ineq_sett &dest,
242  const std::pair<unsigned, unsigned> &eq,
243  const std::pair<unsigned, unsigned> &ineq)
244 {
245  std::pair<unsigned, unsigned> n;
246 
247  // uhuh. Need to try all pairs
248 
249  if(eq.first==ineq.first)
250  {
251  n=ineq;
252  n.first=eq.second;
253  dest.insert(n);
254  }
255 
256  if(eq.first==ineq.second)
257  {
258  n=ineq;
259  n.second=eq.second;
260  dest.insert(n);
261  }
262 
263  if(eq.second==ineq.first)
264  {
265  n=ineq;
266  n.first=eq.first;
267  dest.insert(n);
268  }
269 
270  if(eq.second==ineq.second)
271  {
272  n=ineq;
273  n.second=eq.first;
274  dest.insert(n);
275  }
276 }
277 
278 tvt invariant_sett::is_eq(std::pair<unsigned, unsigned> p) const
279 {
280  std::pair<unsigned, unsigned> s=p;
281  std::swap(s.first, s.second);
282 
283  if(has_eq(p))
284  return tvt(true);
285 
286  if(has_ne(p) || has_ne(s))
287  return tvt(false);
288 
289  return tvt::unknown();
290 }
291 
292 tvt invariant_sett::is_le(std::pair<unsigned, unsigned> p) const
293 {
294  std::pair<unsigned, unsigned> s=p;
295  std::swap(s.first, s.second);
296 
297  if(has_eq(p))
298  return tvt(true);
299 
300  if(has_le(p))
301  return tvt(true);
302 
303  if(has_le(s))
304  if(has_ne(s) || has_ne(p))
305  return tvt(false);
306 
307  return tvt::unknown();
308 }
309 
310 void invariant_sett::output(std::ostream &out) const
311 {
312  if(is_false)
313  {
314  out << "FALSE\n";
315  return;
316  }
317 
318  for(std::size_t i=0; i<eq_set.size(); i++)
319  if(eq_set.is_root(i) &&
320  eq_set.count(i)>=2)
321  {
322  bool first=true;
323  for(std::size_t j=0; j<eq_set.size(); j++)
324  if(eq_set.find(j)==i)
325  {
326  if(first)
327  first=false;
328  else
329  out << " = ";
330 
331  out << to_string(j);
332  }
333 
334  out << '\n';
335  }
336 
337  for(const auto &bounds : bounds_map)
338  {
339  out << to_string(bounds.first) << " in " << bounds.second << '\n';
340  }
341 
342  for(const auto &le : le_set)
343  {
344  out << to_string(le.first) << " <= " << to_string(le.second) << '\n';
345  }
346 
347  for(const auto &ne : ne_set)
348  {
349  out << to_string(ne.first) << " != " << to_string(ne.second) << '\n';
350  }
351 }
352 
353 void invariant_sett::add_type_bounds(const exprt &expr, const typet &type)
354 {
355  if(expr.type()==type)
356  return;
357 
358  if(type.id()==ID_unsignedbv)
359  {
360  std::size_t op_width=to_unsignedbv_type(type).get_width();
361 
362  // TODO - 8 appears to be a magic number here -- or perhaps this should say
363  // ">=" instead, and is meant to restrict types larger than a single byte?
364  if(op_width<=8)
365  {
366  unsigned a;
367  if(get_object(expr, a))
368  return;
369 
370  add_bounds(a, boundst(0, power(2, op_width)-1));
371  }
372  }
373 }
374 
376 {
377  exprt tmp(expr);
378  nnf(tmp);
379  strengthen_rec(tmp);
380 }
381 
383 {
384  if(!expr.is_boolean())
385  throw "non-Boolean argument to strengthen()";
386 
387  #if 0
388  std::cout << "S: " << from_expr(*ns, irep_idt(), expr) << '\n';
389 #endif
390 
391  if(is_false)
392  {
393  // we can't get any stronger
394  return;
395  }
396 
397  if(expr.is_true())
398  {
399  // do nothing, it's useless
400  }
401  else if(expr.is_false())
402  {
403  // wow, that's strong
404  make_false();
405  }
406  else if(expr.id()==ID_not)
407  {
408  // give up, we expect NNF
409  }
410  else if(expr.id()==ID_and)
411  {
412  for(const auto &op : expr.operands())
413  strengthen_rec(op);
414  }
415  else if(expr.id()==ID_le ||
416  expr.id()==ID_lt)
417  {
418  const auto &rel = to_binary_relation_expr(expr);
419 
420  // special rule: x <= (a & b)
421  // implies: x<=a && x<=b
422 
423  if(rel.rhs().id() == ID_bitand)
424  {
425  const exprt &bitand_op = rel.op1();
426 
427  for(const auto &op : bitand_op.operands())
428  {
429  auto tmp(rel);
430  tmp.op1() = op;
431  strengthen_rec(tmp);
432  }
433 
434  return;
435  }
436 
437  std::pair<unsigned, unsigned> p;
438 
439  if(get_object(rel.op0(), p.first) || get_object(rel.op1(), p.second))
440  return;
441 
442  const auto i0 = numeric_cast<mp_integer>(rel.op0());
443  const auto i1 = numeric_cast<mp_integer>(rel.op1());
444 
445  if(expr.id()==ID_le)
446  {
447  if(i0.has_value())
448  add_bounds(p.second, lower_interval(*i0));
449  else if(i1.has_value())
450  add_bounds(p.first, upper_interval(*i1));
451  else
452  add_le(p);
453  }
454  else if(expr.id()==ID_lt)
455  {
456  if(i0.has_value())
457  add_bounds(p.second, lower_interval(*i0 + 1));
458  else if(i1.has_value())
459  add_bounds(p.first, upper_interval(*i1 - 1));
460  else
461  {
462  add_le(p);
463  add_ne(p);
464  }
465  }
466  else
467  UNREACHABLE;
468  }
469  else if(expr.id()==ID_equal)
470  {
471  const auto &equal_expr = to_equal_expr(expr);
472 
473  const typet &op_type = equal_expr.op0().type();
474 
475  if(op_type.id() == ID_struct || op_type.id() == ID_struct_tag)
476  {
477  const struct_typet &struct_type =
478  op_type.id() == ID_struct ? to_struct_type(op_type)
479  : ns.follow_tag(to_struct_tag_type(op_type));
480 
481  for(const auto &comp : struct_type.components())
482  {
483  const member_exprt lhs_member_expr(
484  equal_expr.op0(), comp.get_name(), comp.type());
485  const member_exprt rhs_member_expr(
486  equal_expr.op1(), comp.get_name(), comp.type());
487 
488  const equal_exprt equality(lhs_member_expr, rhs_member_expr);
489 
490  // recursive call
491  strengthen_rec(equality);
492  }
493 
494  return;
495  }
496 
497  // special rule: x = (a & b)
498  // implies: x<=a && x<=b
499 
500  if(equal_expr.op1().id() == ID_bitand)
501  {
502  const exprt &bitand_op = equal_expr.op1();
503 
504  for(const auto &op : bitand_op.operands())
505  {
506  auto tmp(equal_expr);
507  tmp.op1() = op;
508  tmp.id(ID_le);
509  strengthen_rec(tmp);
510  }
511 
512  return;
513  }
514  else if(equal_expr.op0().id() == ID_bitand)
515  {
516  auto tmp(equal_expr);
517  std::swap(tmp.op0(), tmp.op1());
518  strengthen_rec(tmp);
519  return;
520  }
521 
522  // special rule: x = (type) y
523  if(equal_expr.op1().id() == ID_typecast)
524  {
525  const auto &typecast_expr = to_typecast_expr(equal_expr.op1());
526  add_type_bounds(equal_expr.op0(), typecast_expr.op().type());
527  }
528  else if(equal_expr.op0().id() == ID_typecast)
529  {
530  const auto &typecast_expr = to_typecast_expr(equal_expr.op0());
531  add_type_bounds(equal_expr.op1(), typecast_expr.op().type());
532  }
533 
534  std::pair<unsigned, unsigned> p, s;
535 
536  if(
537  get_object(equal_expr.op0(), p.first) ||
538  get_object(equal_expr.op1(), p.second))
539  {
540  return;
541  }
542 
543  const auto i0 = numeric_cast<mp_integer>(equal_expr.op0());
544  const auto i1 = numeric_cast<mp_integer>(equal_expr.op1());
545  if(i0.has_value())
546  add_bounds(p.second, boundst(*i0));
547  else if(i1.has_value())
548  add_bounds(p.first, boundst(*i1));
549 
550  s=p;
551  std::swap(s.first, s.second);
552 
553  // contradiction?
554  if(has_ne(p) || has_ne(s))
555  make_false();
556  else if(!has_eq(p))
557  add_eq(p);
558  }
559  else if(expr.id()==ID_notequal)
560  {
561  const auto &notequal_expr = to_notequal_expr(expr);
562 
563  std::pair<unsigned, unsigned> p;
564 
565  if(
566  get_object(notequal_expr.op0(), p.first) ||
567  get_object(notequal_expr.op1(), p.second))
568  {
569  return;
570  }
571 
572  // check if this is a contradiction
573  if(has_eq(p))
574  make_false();
575  else
576  add_ne(p);
577  }
578 }
579 
581 {
582  exprt tmp(expr);
583  nnf(tmp);
584  return implies_rec(tmp);
585 }
586 
588 {
589  if(!expr.is_boolean())
590  throw "implies: non-Boolean expression";
591 
592  #if 0
593  std::cout << "I: " << from_expr(*ns, irep_idt(), expr) << '\n';
594 #endif
595 
596  if(is_false) // can't get any stronger
597  return tvt(true);
598 
599  if(expr.is_true())
600  return tvt(true);
601  else if(expr.id()==ID_not)
602  {
603  // give up, we expect NNF
604  }
605  else if(expr.id()==ID_and)
606  {
607  for(const auto &op : expr.operands())
608  {
609  if(implies_rec(op) != tvt(true))
610  return tvt::unknown();
611  }
612 
613  return tvt(true);
614  }
615  else if(expr.id()==ID_or)
616  {
617  for(const auto &op : expr.operands())
618  {
619  if(implies_rec(op) == tvt(true))
620  return tvt(true);
621  }
622  }
623  else if(expr.id()==ID_le ||
624  expr.id()==ID_lt ||
625  expr.id()==ID_equal ||
626  expr.id()==ID_notequal)
627  {
628  const auto &rel = to_binary_relation_expr(expr);
629 
630  std::pair<unsigned, unsigned> p;
631 
632  bool ob0 = get_object(rel.lhs(), p.first);
633  bool ob1 = get_object(rel.rhs(), p.second);
634 
635  if(ob0 || ob1)
636  return tvt::unknown();
637 
638  tvt r;
639 
640  if(rel.id() == ID_le)
641  {
642  r=is_le(p);
643  if(!r.is_unknown())
644  return r;
645 
646  boundst b0, b1;
647  get_bounds(p.first, b0);
648  get_bounds(p.second, b1);
649 
650  return b0<=b1;
651  }
652  else if(rel.id() == ID_lt)
653  {
654  r=is_lt(p);
655  if(!r.is_unknown())
656  return r;
657 
658  boundst b0, b1;
659  get_bounds(p.first, b0);
660  get_bounds(p.second, b1);
661 
662  return b0<b1;
663  }
664  else if(rel.id() == ID_equal)
665  return is_eq(p);
666  else if(rel.id() == ID_notequal)
667  return is_ne(p);
668  else
669  UNREACHABLE;
670  }
671 
672  return tvt::unknown();
673 }
674 
675 void invariant_sett::get_bounds(unsigned a, boundst &bounds) const
676 {
677  // unbounded
678  bounds=boundst();
679 
680  {
681  const exprt &e_a = object_store.get_expr(a);
682  const auto tmp = numeric_cast<mp_integer>(e_a);
683  if(tmp.has_value())
684  {
685  bounds = boundst(*tmp);
686  return;
687  }
688 
689  if(e_a.type().id()==ID_unsignedbv)
690  bounds=lower_interval(mp_integer(0));
691  }
692 
693  bounds_mapt::const_iterator it=bounds_map.find(a);
694 
695  if(it!=bounds_map.end())
696  bounds=it->second;
697 }
698 
699 void invariant_sett::nnf(exprt &expr, bool negate)
700 {
701  if(!expr.is_boolean())
702  throw "nnf: non-Boolean expression";
703 
704  if(expr.is_true())
705  {
706  if(negate)
707  expr=false_exprt();
708  }
709  else if(expr.is_false())
710  {
711  if(negate)
712  expr=true_exprt();
713  }
714  else if(expr.id()==ID_not)
715  {
716  nnf(to_not_expr(expr).op(), !negate);
717  exprt tmp;
718  tmp.swap(to_not_expr(expr).op());
719  expr.swap(tmp);
720  }
721  else if(expr.id()==ID_and)
722  {
723  if(negate)
724  expr.id(ID_or);
725 
726  Forall_operands(it, expr)
727  nnf(*it, negate);
728  }
729  else if(expr.id()==ID_or)
730  {
731  if(negate)
732  expr.id(ID_and);
733 
734  Forall_operands(it, expr)
735  nnf(*it, negate);
736  }
737  else if(expr.id()==ID_typecast)
738  {
739  const auto &typecast_expr = to_typecast_expr(expr);
740 
741  if(
742  typecast_expr.op().type().id() == ID_unsignedbv ||
743  typecast_expr.op().type().id() == ID_signedbv)
744  {
745  equal_exprt tmp(
746  typecast_expr.op(), from_integer(0, typecast_expr.op().type()));
747  nnf(tmp, !negate);
748  expr.swap(tmp);
749  }
750  else if(negate)
751  {
752  expr = boolean_negate(expr);
753  }
754  }
755  else if(expr.id()==ID_le)
756  {
757  if(negate)
758  {
759  // !a<=b <-> !b=>a <-> b<a
760  expr.id(ID_lt);
761  auto &rel = to_binary_relation_expr(expr);
762  std::swap(rel.lhs(), rel.rhs());
763  }
764  }
765  else if(expr.id()==ID_lt)
766  {
767  if(negate)
768  {
769  // !a<b <-> !b>a <-> b<=a
770  expr.id(ID_le);
771  auto &rel = to_binary_relation_expr(expr);
772  std::swap(rel.lhs(), rel.rhs());
773  }
774  }
775  else if(expr.id()==ID_ge)
776  {
777  if(negate)
778  expr.id(ID_lt);
779  else
780  {
781  expr.id(ID_le);
782  auto &rel = to_binary_relation_expr(expr);
783  std::swap(rel.lhs(), rel.rhs());
784  }
785  }
786  else if(expr.id()==ID_gt)
787  {
788  if(negate)
789  expr.id(ID_le);
790  else
791  {
792  expr.id(ID_lt);
793  auto &rel = to_binary_relation_expr(expr);
794  std::swap(rel.lhs(), rel.rhs());
795  }
796  }
797  else if(expr.id()==ID_equal)
798  {
799  if(negate)
800  expr.id(ID_notequal);
801  }
802  else if(expr.id()==ID_notequal)
803  {
804  if(negate)
805  expr.id(ID_equal);
806  }
807  else if(negate)
808  {
809  expr = boolean_negate(expr);
810  }
811 }
812 
814  exprt &expr) const
815 {
816  if(expr.id()==ID_address_of)
817  return;
818 
819  Forall_operands(it, expr)
820  simplify(*it);
821 
822  if(expr.id()==ID_symbol ||
823  expr.id()==ID_member)
824  {
825  exprt tmp=get_constant(expr);
826  if(tmp.is_not_nil())
827  expr.swap(tmp);
828  }
829 }
830 
832 {
833  unsigned a;
834 
835  if(!get_object(expr, a))
836  {
837  // bounds?
838  bounds_mapt::const_iterator it=bounds_map.find(a);
839 
840  if(it!=bounds_map.end())
841  {
842  if(it->second.singleton())
843  return from_integer(it->second.get_lower(), expr.type());
844  }
845 
846  unsigned r=eq_set.find(a);
847 
848  // is it a constant?
849  for(std::size_t i=0; i<eq_set.size(); i++)
850  if(eq_set.find(i)==r)
851  {
852  const exprt &e = object_store.get_expr(i);
853 
854  if(e.is_constant())
855  {
856  const mp_integer value =
857  numeric_cast_v<mp_integer>(to_constant_expr(e));
858 
859  if(expr.type().id()==ID_pointer)
860  {
861  if(value==0)
862  return null_pointer_exprt(to_pointer_type(expr.type()));
863  }
864  else
865  return from_integer(value, expr.type());
866  }
868  {
869  if(e.type()==expr.type())
870  return e;
871 
872  return typecast_exprt(e, expr.type());
873  }
874  }
875  }
876 
877  return static_cast<const exprt &>(get_nil_irep());
878 }
879 
880 std::string inv_object_storet::to_string(unsigned a) const
881 {
882  return id2string(map[a]);
883 }
884 
885 std::string invariant_sett::to_string(unsigned a) const
886 {
887  return object_store.to_string(a);
888 }
889 
891 {
892  if(other.threaded &&
893  !threaded)
894  {
895  make_threaded();
896  return true; // change
897  }
898 
899  if(threaded)
900  return false; // no change
901 
902  if(other.is_false)
903  return false; // no change
904 
905  if(is_false)
906  {
907  // copy
908  is_false=false;
909  eq_set=other.eq_set;
910  le_set=other.le_set;
911  ne_set=other.ne_set;
912  bounds_map=other.bounds_map;
913 
914  return true; // change
915  }
916 
917  // equalities first
918  unsigned old_eq_roots=eq_set.count_roots();
919 
920  eq_set.intersection(other.eq_set);
921 
922  // inequalities
923  std::size_t old_ne_set=ne_set.size();
924  std::size_t old_le_set=le_set.size();
925 
926  intersection(ne_set, other.ne_set);
927  intersection(le_set, other.le_set);
928 
929  // bounds
931  return true;
932 
933  if(old_eq_roots!=eq_set.count_roots() ||
934  old_ne_set!=ne_set.size() ||
935  old_le_set!=le_set.size())
936  return true;
937 
938  return false; // no change
939 }
940 
942 {
943  bool changed=false;
944 
945  for(bounds_mapt::iterator
946  it=bounds_map.begin();
947  it!=bounds_map.end();
948  ) // no it++
949  {
950  bounds_mapt::const_iterator o_it=other.find(it->first);
951 
952  if(o_it==other.end())
953  {
954  bounds_mapt::iterator next(it);
955  next++;
956  bounds_map.erase(it);
957  it=next;
958  changed=true;
959  }
960  else
961  {
962  boundst old(it->second);
963  it->second.approx_union_with(o_it->second);
964  if(it->second!=old)
965  changed=true;
966  it++;
967  }
968  }
969 
970  return changed;
971 }
972 
973 void invariant_sett::modifies(unsigned a)
974 {
975  eq_set.isolate(a);
976  remove(ne_set, a);
977  remove(le_set, a);
978  bounds_map.erase(a);
979 }
980 
982 {
983  if(lhs.id()==ID_symbol ||
984  lhs.id()==ID_member)
985  {
986  unsigned a;
987  if(!get_object(lhs, a))
988  modifies(a);
989  }
990  else if(lhs.id()==ID_index)
991  {
992  // we don't track arrays
993  }
994  else if(lhs.id()==ID_dereference)
995  {
996  // be very, very conservative for now
997  make_true();
998  }
999  else if(lhs.id()=="object_value")
1000  {
1001  // be very, very conservative for now
1002  make_true();
1003  }
1004  else if(lhs.id()==ID_if)
1005  {
1006  // we just assume both are changed
1007  modifies(to_if_expr(lhs).op1());
1008  modifies(to_if_expr(lhs).op2());
1009  }
1010  else if(lhs.id()==ID_typecast)
1011  {
1012  // just go down
1013  modifies(to_typecast_expr(lhs).op());
1014  }
1015  else if(lhs.id()=="valid_object")
1016  {
1017  }
1018  else if(lhs.id()==ID_byte_extract_little_endian ||
1019  lhs.id()==ID_byte_extract_big_endian)
1020  {
1021  // just go down
1022  modifies(to_byte_extract_expr(lhs).op0());
1023  }
1024  else if(lhs.id() == ID_null_object ||
1025  lhs.id() == "is_zero_string" ||
1026  lhs.id() == "zero_string" ||
1027  lhs.id() == "zero_string_length")
1028  {
1029  // ignore
1030  }
1031  else
1032  throw "modifies: unexpected lhs: "+lhs.id_string();
1033 }
1034 
1036  const exprt &lhs,
1037  const exprt &rhs)
1038 {
1039  equal_exprt equality(lhs, rhs);
1040 
1041  // first evaluate RHS
1042  simplify(equality.rhs());
1043  ::simplify(equality.rhs(), ns);
1044 
1045  // now kill LHS
1046  modifies(lhs);
1047 
1048  // and put it back
1049  strengthen(equality);
1050 }
1051 
1053 {
1054  const irep_idt &statement=code.get(ID_statement);
1055 
1056  if(statement==ID_block)
1057  {
1058  for(const auto &op : code.operands())
1059  apply_code(to_code(op));
1060  }
1061  else if(statement==ID_assign)
1062  {
1063  if(code.operands().size()!=2)
1064  throw "assignment expected to have two operands";
1065 
1066  assignment(code.op0(), code.op1());
1067  }
1068  else if(statement==ID_decl)
1069  {
1070  if(code.operands().size()==2)
1071  assignment(code.op0(), code.op1());
1072  else
1073  modifies(code.op0());
1074  }
1075  else if(statement==ID_expression)
1076  {
1077  // this never modifies anything
1078  }
1079  else if(statement==ID_function_call)
1080  {
1081  // may be a disaster
1082  make_true();
1083  }
1084  else if(statement==ID_cpp_delete ||
1085  statement==ID_cpp_delete_array)
1086  {
1087  // does nothing
1088  }
1089  else if(statement==ID_printf)
1090  {
1091  // does nothing
1092  }
1093  else if(statement=="lock" ||
1094  statement=="unlock" ||
1095  statement==ID_asm)
1096  {
1097  // ignore for now
1098  }
1099  else
1100  {
1101  std::cerr << code.pretty() << '\n';
1102  throw "invariant_sett: unexpected statement: "+id2string(statement);
1103  }
1104 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:99
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const unsignedbv_typet & to_unsignedbv_type(const typet &type)
Cast a typet to an unsignedbv_typet.
Expression classes for byte-level operators.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
exprt & rhs()
Definition: std_expr.h:678
std::size_t get_width() const
Definition: std_types.h:925
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:29
exprt & op1()
Definition: expr.h:136
exprt & op0()
Definition: expr.h:133
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Equality.
Definition: std_expr.h:1366
Base class for all expressions.
Definition: expr.h:56
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:27
exprt & op1()
Definition: expr.h:136
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition: expr.h:224
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:34
typet & type()
Return the type of the expression.
Definition: expr.h:84
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.h:212
operandst & operands()
Definition: expr.h:94
The Boolean constant false.
Definition: std_expr.h:3082
void output(std::ostream &out) const
static bool is_constant_address_rec(const exprt &expr)
static bool is_constant_address(const exprt &expr)
std::string build_string(const exprt &expr) const
std::string to_string(unsigned n) const
unsigned add(const exprt &expr)
const exprt & get_expr(unsigned n) const
Definition: invariant_set.h:50
std::vector< entryt > entries
Definition: invariant_set.h:72
bool is_constant(unsigned n) const
bool get(const exprt &expr, unsigned &n)
const namespacet & ns
Definition: invariant_set.h:61
inv_object_storet & object_store
tvt is_lt(std::pair< unsigned, unsigned > p) const
tvt is_le(std::pair< unsigned, unsigned > p) const
void add_ne(const std::pair< unsigned, unsigned > &p)
bool has_le(const std::pair< unsigned, unsigned > &p) const
tvt implies_rec(const exprt &expr) const
void apply_code(const codet &code)
unsigned_union_find eq_set
Definition: invariant_set.h:83
std::map< unsigned, boundst > bounds_mapt
Definition: invariant_set.h:94
ineq_sett ne_set
Definition: invariant_set.h:90
exprt get_constant(const exprt &expr) const
tvt is_ne(std::pair< unsigned, unsigned > p) const
interval_templatet< mp_integer > boundst
Definition: invariant_set.h:93
ineq_sett le_set
Definition: invariant_set.h:87
void simplify(exprt &expr) const
void output(std::ostream &out) const
void add_bounds(unsigned a, const boundst &bound)
bool make_union(const invariant_sett &other_invariants)
void strengthen(const exprt &expr)
void make_threaded()
void assignment(const exprt &lhs, const exprt &rhs)
void add_eq(const std::pair< unsigned, unsigned > &eq)
static void intersection(ineq_sett &dest, const ineq_sett &other)
bounds_mapt bounds_map
Definition: invariant_set.h:95
std::set< std::pair< unsigned, unsigned > > ineq_sett
Definition: invariant_set.h:86
static void nnf(exprt &expr, bool negate=false)
const namespacet & ns
void get_bounds(unsigned a, boundst &dest) const
static void remove(ineq_sett &dest, unsigned a)
tvt implies(const exprt &expr) const
void add(const std::pair< unsigned, unsigned > &p, ineq_sett &dest)
void add_type_bounds(const exprt &expr, const typet &type)
void add_le(const std::pair< unsigned, unsigned > &p)
bool has_ne(const std::pair< unsigned, unsigned > &p) const
bool get_object(const exprt &expr, unsigned &n) const
bool make_union_bounds_map(const bounds_mapt &other)
std::string to_string(unsigned a) const
void modifies(const exprt &lhs)
void strengthen_rec(const exprt &expr)
bool has_eq(const std::pair< unsigned, unsigned > &p) const
tvt is_eq(std::pair< unsigned, unsigned > p) const
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:482
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
const std::string & id_string() const
Definition: irep.h:391
bool is_not_nil() const
Definition: irep.h:372
const irep_idt & id() const
Definition: irep.h:388
void swap(irept &irep)
Definition: irep.h:434
const std::string & get_string(const irep_idt &name) const
Definition: irep.h:401
Extract member of struct or union.
Definition: std_expr.h:2854
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
The null pointer constant.
Definition: pointer_expr.h:909
number_type number(const key_type &a)
Definition: numbering.h:37
std::optional< number_type > get_number(const key_type &a) const
Definition: numbering.h:50
std::size_t number_type
Definition: numbering.h:24
Structure type, corresponds to C style structs.
Definition: std_types.h:231
const componentst & components() const
Definition: std_types.h:147
The Boolean constant true.
Definition: std_expr.h:3073
Definition: threeval.h:20
static tvt unknown()
Definition: threeval.h:33
Semantic type conversion.
Definition: std_expr.h:2073
The type of an expression, extends irept.
Definition: type.h:29
void intersection(const unsigned_union_find &other)
Definition: union_find.cpp:120
size_type size() const
Definition: union_find.h:97
void check_index(size_type a)
Definition: union_find.h:111
size_type find(size_type a) const
Definition: union_find.cpp:141
size_type count(size_type a) const
Definition: union_find.h:103
size_type count_roots() const
Definition: union_find.h:118
bool is_root(size_type a) const
Definition: union_find.h:82
void make_union(size_type a, size_type b)
Definition: union_find.cpp:13
void isolate(size_type a)
Definition: union_find.cpp:41
#define Forall_operands(it, expr)
Definition: expr.h:27
exprt boolean_negate(const exprt &src)
negate a Boolean expression, possibly removing a not_exprt, and swapping false and true
Definition: expr_util.cpp:103
bool is_null_pointer(const constant_exprt &expr)
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Definition: expr_util.cpp:344
Deprecated expression utility functions.
interval_templatet< T > lower_interval(const T &l)
interval_templatet< T > upper_interval(const T &u)
Value Set.
const irept & get_nil_irep()
Definition: irep.cpp:19
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
static int8_t r
Definition: irep_hash.h:60
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
const std::string integer2string(const mp_integer &n, unsigned base)
Definition: mp_arith.cpp:103
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
BigInt mp_integer
Definition: smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
const codet & to_code(const exprt &expr)
const notequal_exprt & to_notequal_expr(const exprt &expr)
Cast an exprt to an notequal_exprt.
Definition: std_expr.h:1450
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2460
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3055
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2107
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition: std_expr.h:2362
const equal_exprt & to_equal_expr(const exprt &expr)
Cast an exprt to an equal_exprt.
Definition: std_expr.h:1407
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2946
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition: std_expr.h:895
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1538
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:518
dstringt irep_idt