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 <iostream>
15 
16 #include <util/arith_tools.h>
17 #include <util/byte_operators.h>
18 #include <util/expr_util.h>
19 #include <util/namespace.h>
20 #include <util/pointer_expr.h>
21 #include <util/simplify_expr.h>
22 #include <util/std_code.h>
23 
24 #include <langapi/language_util.h>
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  assert(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.type().id()!=ID_bool)
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  forall_operands(it, expr)
413  strengthen_rec(*it);
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  forall_operands(it, bitand_op)
428  {
429  auto tmp(rel);
430  tmp.op1()=*it;
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 = to_struct_type(ns.follow(op_type));
478 
479  for(const auto &comp : struct_type.components())
480  {
481  const member_exprt lhs_member_expr(
482  equal_expr.op0(), comp.get_name(), comp.type());
483  const member_exprt rhs_member_expr(
484  equal_expr.op1(), comp.get_name(), comp.type());
485 
486  const equal_exprt equality(lhs_member_expr, rhs_member_expr);
487 
488  // recursive call
489  strengthen_rec(equality);
490  }
491 
492  return;
493  }
494 
495  // special rule: x = (a & b)
496  // implies: x<=a && x<=b
497 
498  if(equal_expr.op1().id() == ID_bitand)
499  {
500  const exprt &bitand_op = equal_expr.op1();
501 
502  forall_operands(it, bitand_op)
503  {
504  auto tmp(equal_expr);
505  tmp.op1()=*it;
506  tmp.id(ID_le);
507  strengthen_rec(tmp);
508  }
509 
510  return;
511  }
512  else if(equal_expr.op0().id() == ID_bitand)
513  {
514  auto tmp(equal_expr);
515  std::swap(tmp.op0(), tmp.op1());
516  strengthen_rec(tmp);
517  return;
518  }
519 
520  // special rule: x = (type) y
521  if(equal_expr.op1().id() == ID_typecast)
522  {
523  const auto &typecast_expr = to_typecast_expr(equal_expr.op1());
524  add_type_bounds(equal_expr.op0(), typecast_expr.op().type());
525  }
526  else if(equal_expr.op0().id() == ID_typecast)
527  {
528  const auto &typecast_expr = to_typecast_expr(equal_expr.op0());
529  add_type_bounds(equal_expr.op1(), typecast_expr.op().type());
530  }
531 
532  std::pair<unsigned, unsigned> p, s;
533 
534  if(
535  get_object(equal_expr.op0(), p.first) ||
536  get_object(equal_expr.op1(), p.second))
537  {
538  return;
539  }
540 
541  const auto i0 = numeric_cast<mp_integer>(equal_expr.op0());
542  const auto i1 = numeric_cast<mp_integer>(equal_expr.op1());
543  if(i0.has_value())
544  add_bounds(p.second, boundst(*i0));
545  else if(i1.has_value())
546  add_bounds(p.first, boundst(*i1));
547 
548  s=p;
549  std::swap(s.first, s.second);
550 
551  // contradiction?
552  if(has_ne(p) || has_ne(s))
553  make_false();
554  else if(!has_eq(p))
555  add_eq(p);
556  }
557  else if(expr.id()==ID_notequal)
558  {
559  const auto &notequal_expr = to_notequal_expr(expr);
560 
561  std::pair<unsigned, unsigned> p;
562 
563  if(
564  get_object(notequal_expr.op0(), p.first) ||
565  get_object(notequal_expr.op1(), p.second))
566  {
567  return;
568  }
569 
570  // check if this is a contradiction
571  if(has_eq(p))
572  make_false();
573  else
574  add_ne(p);
575  }
576 }
577 
579 {
580  exprt tmp(expr);
581  nnf(tmp);
582  return implies_rec(tmp);
583 }
584 
586 {
587  if(expr.type().id()!=ID_bool)
588  throw "implies: non-Boolean expression";
589 
590  #if 0
591  std::cout << "I: " << from_expr(*ns, irep_idt(), expr) << '\n';
592 #endif
593 
594  if(is_false) // can't get any stronger
595  return tvt(true);
596 
597  if(expr.is_true())
598  return tvt(true);
599  else if(expr.id()==ID_not)
600  {
601  // give up, we expect NNF
602  }
603  else if(expr.id()==ID_and)
604  {
605  forall_operands(it, expr)
606  if(implies_rec(*it)!=tvt(true))
607  return tvt::unknown();
608 
609  return tvt(true);
610  }
611  else if(expr.id()==ID_or)
612  {
613  forall_operands(it, expr)
614  if(implies_rec(*it)==tvt(true))
615  return tvt(true);
616  }
617  else if(expr.id()==ID_le ||
618  expr.id()==ID_lt ||
619  expr.id()==ID_equal ||
620  expr.id()==ID_notequal)
621  {
622  const auto &rel = to_binary_relation_expr(expr);
623 
624  std::pair<unsigned, unsigned> p;
625 
626  bool ob0 = get_object(rel.lhs(), p.first);
627  bool ob1 = get_object(rel.rhs(), p.second);
628 
629  if(ob0 || ob1)
630  return tvt::unknown();
631 
632  tvt r;
633 
634  if(rel.id() == ID_le)
635  {
636  r=is_le(p);
637  if(!r.is_unknown())
638  return r;
639 
640  boundst b0, b1;
641  get_bounds(p.first, b0);
642  get_bounds(p.second, b1);
643 
644  return b0<=b1;
645  }
646  else if(rel.id() == ID_lt)
647  {
648  r=is_lt(p);
649  if(!r.is_unknown())
650  return r;
651 
652  boundst b0, b1;
653  get_bounds(p.first, b0);
654  get_bounds(p.second, b1);
655 
656  return b0<b1;
657  }
658  else if(rel.id() == ID_equal)
659  return is_eq(p);
660  else if(rel.id() == ID_notequal)
661  return is_ne(p);
662  else
663  UNREACHABLE;
664  }
665 
666  return tvt::unknown();
667 }
668 
669 void invariant_sett::get_bounds(unsigned a, boundst &bounds) const
670 {
671  // unbounded
672  bounds=boundst();
673 
674  {
675  const exprt &e_a = object_store.get_expr(a);
676  const auto tmp = numeric_cast<mp_integer>(e_a);
677  if(tmp.has_value())
678  {
679  bounds = boundst(*tmp);
680  return;
681  }
682 
683  if(e_a.type().id()==ID_unsignedbv)
684  bounds=lower_interval(mp_integer(0));
685  }
686 
687  bounds_mapt::const_iterator it=bounds_map.find(a);
688 
689  if(it!=bounds_map.end())
690  bounds=it->second;
691 }
692 
693 void invariant_sett::nnf(exprt &expr, bool negate)
694 {
695  if(expr.type().id()!=ID_bool)
696  throw "nnf: non-Boolean expression";
697 
698  if(expr.is_true())
699  {
700  if(negate)
701  expr=false_exprt();
702  }
703  else if(expr.is_false())
704  {
705  if(negate)
706  expr=true_exprt();
707  }
708  else if(expr.id()==ID_not)
709  {
710  nnf(to_not_expr(expr).op(), !negate);
711  exprt tmp;
712  tmp.swap(to_not_expr(expr).op());
713  expr.swap(tmp);
714  }
715  else if(expr.id()==ID_and)
716  {
717  if(negate)
718  expr.id(ID_or);
719 
720  Forall_operands(it, expr)
721  nnf(*it, negate);
722  }
723  else if(expr.id()==ID_or)
724  {
725  if(negate)
726  expr.id(ID_and);
727 
728  Forall_operands(it, expr)
729  nnf(*it, negate);
730  }
731  else if(expr.id()==ID_typecast)
732  {
733  const auto &typecast_expr = to_typecast_expr(expr);
734 
735  if(
736  typecast_expr.op().type().id() == ID_unsignedbv ||
737  typecast_expr.op().type().id() == ID_signedbv)
738  {
739  equal_exprt tmp(
740  typecast_expr.op(), from_integer(0, typecast_expr.op().type()));
741  nnf(tmp, !negate);
742  expr.swap(tmp);
743  }
744  else if(negate)
745  {
746  expr = boolean_negate(expr);
747  }
748  }
749  else if(expr.id()==ID_le)
750  {
751  if(negate)
752  {
753  // !a<=b <-> !b=>a <-> b<a
754  expr.id(ID_lt);
755  auto &rel = to_binary_relation_expr(expr);
756  std::swap(rel.lhs(), rel.rhs());
757  }
758  }
759  else if(expr.id()==ID_lt)
760  {
761  if(negate)
762  {
763  // !a<b <-> !b>a <-> b<=a
764  expr.id(ID_le);
765  auto &rel = to_binary_relation_expr(expr);
766  std::swap(rel.lhs(), rel.rhs());
767  }
768  }
769  else if(expr.id()==ID_ge)
770  {
771  if(negate)
772  expr.id(ID_lt);
773  else
774  {
775  expr.id(ID_le);
776  auto &rel = to_binary_relation_expr(expr);
777  std::swap(rel.lhs(), rel.rhs());
778  }
779  }
780  else if(expr.id()==ID_gt)
781  {
782  if(negate)
783  expr.id(ID_le);
784  else
785  {
786  expr.id(ID_lt);
787  auto &rel = to_binary_relation_expr(expr);
788  std::swap(rel.lhs(), rel.rhs());
789  }
790  }
791  else if(expr.id()==ID_equal)
792  {
793  if(negate)
794  expr.id(ID_notequal);
795  }
796  else if(expr.id()==ID_notequal)
797  {
798  if(negate)
799  expr.id(ID_equal);
800  }
801  else if(negate)
802  {
803  expr = boolean_negate(expr);
804  }
805 }
806 
808  exprt &expr) const
809 {
810  if(expr.id()==ID_address_of)
811  return;
812 
813  Forall_operands(it, expr)
814  simplify(*it);
815 
816  if(expr.id()==ID_symbol ||
817  expr.id()==ID_member)
818  {
819  exprt tmp=get_constant(expr);
820  if(tmp.is_not_nil())
821  expr.swap(tmp);
822  }
823 }
824 
826 {
827  unsigned a;
828 
829  if(!get_object(expr, a))
830  {
831  // bounds?
832  bounds_mapt::const_iterator it=bounds_map.find(a);
833 
834  if(it!=bounds_map.end())
835  {
836  if(it->second.singleton())
837  return from_integer(it->second.get_lower(), expr.type());
838  }
839 
840  unsigned r=eq_set.find(a);
841 
842  // is it a constant?
843  for(std::size_t i=0; i<eq_set.size(); i++)
844  if(eq_set.find(i)==r)
845  {
846  const exprt &e = object_store.get_expr(i);
847 
848  if(e.is_constant())
849  {
850  const mp_integer value =
851  numeric_cast_v<mp_integer>(to_constant_expr(e));
852 
853  if(expr.type().id()==ID_pointer)
854  {
855  if(value==0)
856  return null_pointer_exprt(to_pointer_type(expr.type()));
857  }
858  else
859  return from_integer(value, expr.type());
860  }
862  {
863  if(e.type()==expr.type())
864  return e;
865 
866  return typecast_exprt(e, expr.type());
867  }
868  }
869  }
870 
871  return static_cast<const exprt &>(get_nil_irep());
872 }
873 
874 std::string inv_object_storet::to_string(unsigned a) const
875 {
876  return id2string(map[a]);
877 }
878 
879 std::string invariant_sett::to_string(unsigned a) const
880 {
881  return object_store.to_string(a);
882 }
883 
885 {
886  if(other.threaded &&
887  !threaded)
888  {
889  make_threaded();
890  return true; // change
891  }
892 
893  if(threaded)
894  return false; // no change
895 
896  if(other.is_false)
897  return false; // no change
898 
899  if(is_false)
900  {
901  // copy
902  is_false=false;
903  eq_set=other.eq_set;
904  le_set=other.le_set;
905  ne_set=other.ne_set;
906  bounds_map=other.bounds_map;
907 
908  return true; // change
909  }
910 
911  // equalities first
912  unsigned old_eq_roots=eq_set.count_roots();
913 
914  eq_set.intersection(other.eq_set);
915 
916  // inequalities
917  std::size_t old_ne_set=ne_set.size();
918  std::size_t old_le_set=le_set.size();
919 
920  intersection(ne_set, other.ne_set);
921  intersection(le_set, other.le_set);
922 
923  // bounds
925  return true;
926 
927  if(old_eq_roots!=eq_set.count_roots() ||
928  old_ne_set!=ne_set.size() ||
929  old_le_set!=le_set.size())
930  return true;
931 
932  return false; // no change
933 }
934 
936 {
937  bool changed=false;
938 
939  for(bounds_mapt::iterator
940  it=bounds_map.begin();
941  it!=bounds_map.end();
942  ) // no it++
943  {
944  bounds_mapt::const_iterator o_it=other.find(it->first);
945 
946  if(o_it==other.end())
947  {
948  bounds_mapt::iterator next(it);
949  next++;
950  bounds_map.erase(it);
951  it=next;
952  changed=true;
953  }
954  else
955  {
956  boundst old(it->second);
957  it->second.approx_union_with(o_it->second);
958  if(it->second!=old)
959  changed=true;
960  it++;
961  }
962  }
963 
964  return changed;
965 }
966 
967 void invariant_sett::modifies(unsigned a)
968 {
969  eq_set.isolate(a);
970  remove(ne_set, a);
971  remove(le_set, a);
972  bounds_map.erase(a);
973 }
974 
976 {
977  if(lhs.id()==ID_symbol ||
978  lhs.id()==ID_member)
979  {
980  unsigned a;
981  if(!get_object(lhs, a))
982  modifies(a);
983  }
984  else if(lhs.id()==ID_index)
985  {
986  // we don't track arrays
987  }
988  else if(lhs.id()==ID_dereference)
989  {
990  // be very, very conservative for now
991  make_true();
992  }
993  else if(lhs.id()=="object_value")
994  {
995  // be very, very conservative for now
996  make_true();
997  }
998  else if(lhs.id()==ID_if)
999  {
1000  // we just assume both are changed
1001  modifies(to_if_expr(lhs).op1());
1002  modifies(to_if_expr(lhs).op2());
1003  }
1004  else if(lhs.id()==ID_typecast)
1005  {
1006  // just go down
1007  modifies(to_typecast_expr(lhs).op());
1008  }
1009  else if(lhs.id()=="valid_object")
1010  {
1011  }
1012  else if(lhs.id()==ID_byte_extract_little_endian ||
1013  lhs.id()==ID_byte_extract_big_endian)
1014  {
1015  // just go down
1016  modifies(to_byte_extract_expr(lhs).op0());
1017  }
1018  else if(lhs.id() == ID_null_object ||
1019  lhs.id() == "is_zero_string" ||
1020  lhs.id() == "zero_string" ||
1021  lhs.id() == "zero_string_length")
1022  {
1023  // ignore
1024  }
1025  else
1026  throw "modifies: unexpected lhs: "+lhs.id_string();
1027 }
1028 
1030  const exprt &lhs,
1031  const exprt &rhs)
1032 {
1033  equal_exprt equality(lhs, rhs);
1034 
1035  // first evaluate RHS
1036  simplify(equality.rhs());
1037  ::simplify(equality.rhs(), ns);
1038 
1039  // now kill LHS
1040  modifies(lhs);
1041 
1042  // and put it back
1043  strengthen(equality);
1044 }
1045 
1047 {
1048  const irep_idt &statement=code.get(ID_statement);
1049 
1050  if(statement==ID_block)
1051  {
1052  forall_operands(it, code)
1053  apply_code(to_code(*it));
1054  }
1055  else if(statement==ID_assign)
1056  {
1057  if(code.operands().size()!=2)
1058  throw "assignment expected to have two operands";
1059 
1060  assignment(code.op0(), code.op1());
1061  }
1062  else if(statement==ID_decl)
1063  {
1064  if(code.operands().size()==2)
1065  assignment(code.op0(), code.op1());
1066  else
1067  modifies(code.op0());
1068  }
1069  else if(statement==ID_expression)
1070  {
1071  // this never modifies anything
1072  }
1073  else if(statement==ID_function_call)
1074  {
1075  // may be a disaster
1076  make_true();
1077  }
1078  else if(statement==ID_cpp_delete ||
1079  statement==ID_cpp_delete_array)
1080  {
1081  // does nothing
1082  }
1083  else if(statement==ID_printf)
1084  {
1085  // does nothing
1086  }
1087  else if(statement=="lock" ||
1088  statement=="unlock" ||
1089  statement==ID_asm)
1090  {
1091  // ignore for now
1092  }
1093  else
1094  {
1095  std::cerr << code.pretty() << '\n';
1096  throw "invariant_sett: unexpected statement: "+id2string(statement);
1097  }
1098 }
UNREACHABLE
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
struct_union_typet::components
const componentst & components() const
Definition: std_types.h:147
invariant_sett::strengthen
void strengthen(const exprt &expr)
Definition: invariant_set.cpp:375
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
to_unsignedbv_type
const unsignedbv_typet & to_unsignedbv_type(const typet &type)
Cast a typet to an unsignedbv_typet.
Definition: bitvector_types.h:191
invariant_sett::boundst
interval_templatet< mp_integer > boundst
Definition: invariant_set.h:93
unsigned_union_find::find
size_type find(size_type a) const
Definition: union_find.cpp:141
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
binary_exprt::rhs
exprt & rhs()
Definition: std_expr.h:623
Forall_operands
#define Forall_operands(it, expr)
Definition: expr.h:27
arith_tools.h
codet::op0
exprt & op0()
Definition: expr.h:125
to_struct_type
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
invariant_sett::implies
tvt implies(const exprt &expr) const
Definition: invariant_set.cpp:578
invariant_sett::ineq_sett
std::set< std::pair< unsigned, unsigned > > ineq_sett
Definition: invariant_set.h:86
CHECK_RETURN
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
invariant_sett::get_bounds
void get_bounds(unsigned a, boundst &dest) const
Definition: invariant_set.cpp:669
unsigned_union_find::check_index
void check_index(size_type a)
Definition: union_find.h:111
typet
The type of an expression, extends irept.
Definition: type.h:28
irept::pretty
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:495
invariant_sett::add_type_bounds
void add_type_bounds(const exprt &expr, const typet &type)
Definition: invariant_set.cpp:353
to_byte_extract_expr
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
Definition: byte_operators.h:57
invariant_sett::make_threaded
void make_threaded()
Definition: invariant_set.h:135
invariant_sett::is_lt
tvt is_lt(std::pair< unsigned, unsigned > p) const
Definition: invariant_set.h:237
to_index_expr
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1478
to_if_expr
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2403
invariant_sett::object_store
inv_object_storet & object_store
Definition: invariant_set.h:189
invariant_sett::threaded
bool threaded
Definition: invariant_set.h:97
unsigned_union_find::size
size_type size() const
Definition: union_find.h:97
exprt
Base class for all expressions.
Definition: expr.h:55
inv_object_storet::to_string
std::string to_string(unsigned n) const
Definition: invariant_set.cpp:874
unsigned_union_find::intersection
void intersection(const unsigned_union_find &other)
Definition: union_find.cpp:120
invariant_sett::is_le
tvt is_le(std::pair< unsigned, unsigned > p) const
Definition: invariant_set.cpp:292
irep_idt
dstringt irep_idt
Definition: irep.h:37
invariant_sett::output
void output(std::ostream &out) const
Definition: invariant_set.cpp:310
invariant_sett::make_union_bounds_map
bool make_union_bounds_map(const bounds_mapt &other)
Definition: invariant_set.cpp:935
exprt::is_true
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:34
to_bitvector_type
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
Definition: bitvector_types.h:32
namespace.h
inv_object_storet::map
mapt map
Definition: invariant_set.h:64
equal_exprt
Equality.
Definition: std_expr.h:1305
invariant_sett::nnf
static void nnf(exprt &expr, bool negate=false)
Definition: invariant_set.cpp:693
inv_object_storet::entries
std::vector< entryt > entries
Definition: invariant_set.h:72
exprt::is_false
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:43
invariant_sett::apply_code
void apply_code(const codet &code)
Definition: invariant_set.cpp:1046
irept::get
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
interval_templatet
Definition: interval_template.h:19
to_code
const codet & to_code(const exprt &expr)
Definition: std_code_base.h:104
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
irept::is_not_nil
bool is_not_nil() const
Definition: irep.h:380
inv_object_storet::add
unsigned add(const exprt &expr)
Definition: invariant_set.cpp:61
unsigned_union_find::count
size_type count(size_type a) const
Definition: union_find.h:103
byte_operators.h
Expression classes for byte-level operators.
invariant_sett::intersection
static void intersection(ineq_sett &dest, const ineq_sett &other)
Definition: invariant_set.h:151
invariant_sett::is_false
bool is_false
Definition: invariant_set.h:98
invariant_sett::eq_set
unsigned_union_find eq_set
Definition: invariant_set.h:83
invariant_sett::add_le
void add_le(const std::pair< unsigned, unsigned > &p)
Definition: invariant_set.h:260
null_pointer_exprt
The null pointer constant.
Definition: pointer_expr.h:734
id2string
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
unsigned_union_find::make_union
void make_union(size_type a, size_type b)
Definition: union_find.cpp:13
get_identifier
static optionalt< smt_termt > get_identifier(const exprt &expr, const std::unordered_map< exprt, smt_identifier_termt, irep_hash > &expression_handle_identifiers, const std::unordered_map< exprt, smt_identifier_termt, irep_hash > &expression_identifiers)
Definition: smt2_incremental_decision_procedure.cpp:328
forall_operands
#define forall_operands(it, expr)
Definition: expr.h:20
language_util.h
invariant_sett::add_eq
void add_eq(const std::pair< unsigned, unsigned > &eq)
Definition: invariant_set.cpp:203
inv_object_storet::get_expr
const exprt & get_expr(unsigned n) const
Definition: invariant_set.h:50
boolean_negate
exprt boolean_negate(const exprt &src)
negate a Boolean expression, possibly removing a not_exprt, and swapping false and true
Definition: expr_util.cpp:127
inv_object_storet::get
bool get(const exprt &expr, unsigned &n)
Definition: invariant_set.cpp:32
pointer_expr.h
irept::id_string
const std::string & id_string() const
Definition: irep.h:399
exprt::op1
exprt & op1()
Definition: expr.h:128
to_notequal_expr
const notequal_exprt & to_notequal_expr(const exprt &expr)
Cast an exprt to an notequal_exprt.
Definition: std_expr.h:1390
to_pointer_type
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:79
irept::get_string
const std::string & get_string(const irep_idt &name) const
Definition: irep.h:409
invariant_sett::ns
const namespacet & ns
Definition: invariant_set.h:190
irept::swap
void swap(irept &irep)
Definition: irep.h:442
to_symbol_expr
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:222
irept::id
const irep_idt & id() const
Definition: irep.h:396
invariant_sett::modifies
void modifies(const exprt &lhs)
Definition: invariant_set.cpp:975
inv_object_storet::is_constant
bool is_constant(unsigned n) const
Definition: invariant_set.cpp:78
tvt::unknown
static tvt unknown()
Definition: threeval.h:33
false_exprt
The Boolean constant false.
Definition: std_expr.h:3016
numberingt::get_number
optionalt< number_type > get_number(const key_type &a) const
Definition: numbering.h:50
invariant_sett::to_string
std::string to_string(unsigned a) const
Definition: invariant_set.cpp:879
invariant_sett::remove
static void remove(ineq_sett &dest, unsigned a)
Definition: invariant_set.h:167
invariant_sett::implies_rec
tvt implies_rec(const exprt &expr) const
Definition: invariant_set.cpp:585
std_code.h
invariant_sett::add_ne
void add_ne(const std::pair< unsigned, unsigned > &p)
Definition: invariant_set.h:265
tvt
Definition: threeval.h:19
invariant_sett::has_le
bool has_le(const std::pair< unsigned, unsigned > &p) const
Definition: invariant_set.h:224
inv_object_storet::output
void output(std::ostream &out) const
Definition: invariant_set.cpp:26
simplify_expr.h
bitvector_typet::get_width
std::size_t get_width() const
Definition: std_types.h:876
invariant_sett::add
void add(const std::pair< unsigned, unsigned > &p, ineq_sett &dest)
Definition: invariant_set.cpp:181
lower_interval
interval_templatet< T > lower_interval(const T &l)
Definition: interval_template.h:262
invariant_sett::bounds_mapt
std::map< unsigned, boundst > bounds_mapt
Definition: invariant_set.h:94
invariant_sett::make_false
void make_false()
Definition: invariant_set.h:127
member_exprt
Extract member of struct or union.
Definition: std_expr.h:2793
expr_util.h
Deprecated expression utility functions.
invariant_sett::le_set
ineq_sett le_set
Definition: invariant_set.h:87
invariant_sett::ne_set
ineq_sett ne_set
Definition: invariant_set.h:90
struct_typet
Structure type, corresponds to C style structs.
Definition: std_types.h:230
invariant_sett
Definition: invariant_set.h:79
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
to_not_expr
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition: std_expr.h:2303
invariant_sett::assignment
void assignment(const exprt &lhs, const exprt &rhs)
Definition: invariant_set.cpp:1029
numberingt::number
number_type number(const key_type &a)
Definition: numbering.h:37
inv_object_storet::build_string
std::string build_string(const exprt &expr) const
Definition: invariant_set.cpp:90
unsigned_union_find::count_roots
size_type count_roots() const
Definition: union_find.h:118
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
to_typecast_expr
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2051
exprt::is_constant
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.cpp:27
invariant_sett::simplify
void simplify(exprt &expr) const
Definition: invariant_set.cpp:807
power
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
Definition: arith_tools.cpp:195
to_equal_expr
const equal_exprt & to_equal_expr(const exprt &expr)
Cast an exprt to an equal_exprt.
Definition: std_expr.h:1347
invariant_sett::get_object
bool get_object(const exprt &expr, unsigned &n) const
Definition: invariant_set.cpp:150
invariant_sett::make_union
bool make_union(const invariant_sett &other_invariants)
Definition: invariant_set.cpp:884
to_member_expr
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2886
get_nil_irep
const irept & get_nil_irep()
Definition: irep.cpp:20
invariant_sett::is_ne
tvt is_ne(std::pair< unsigned, unsigned > p) const
Definition: invariant_set.h:253
to_address_of_expr
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:408
exprt::operands
operandst & operands()
Definition: expr.h:94
r
static int8_t r
Definition: irep_hash.h:60
unsigned_union_find::is_root
bool is_root(size_type a) const
Definition: union_find.h:82
codet::op1
exprt & op1()
Definition: expr.h:128
is_null_pointer
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:315
invariant_sett::get_constant
exprt get_constant(const exprt &expr) const
Definition: invariant_set.cpp:825
inv_object_storet::is_constant_address_rec
static bool is_constant_address_rec(const exprt &expr)
Definition: invariant_set.cpp:165
typecast_exprt
Semantic type conversion.
Definition: std_expr.h:2016
true_exprt
The Boolean constant true.
Definition: std_expr.h:3007
inv_object_storet::ns
const namespacet & ns
Definition: invariant_set.h:61
unsigned_union_find::isolate
void isolate(size_type a)
Definition: union_find.cpp:41
invariant_sett::strengthen_rec
void strengthen_rec(const exprt &expr)
Definition: invariant_set.cpp:382
invariant_sett::bounds_map
bounds_mapt bounds_map
Definition: invariant_set.h:95
invariant_sett::is_eq
tvt is_eq(std::pair< unsigned, unsigned > p) const
Definition: invariant_set.cpp:278
to_binary_relation_expr
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition: std_expr.h:840
invariant_set.h
inv_object_storet::is_constant_address
static bool is_constant_address(const exprt &expr)
Definition: invariant_set.cpp:157
from_expr
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
Definition: language_util.cpp:38
invariant_sett::add_bounds
void add_bounds(unsigned a, const boundst &bound)
Definition: invariant_set.h:198
invariant_sett::has_ne
bool has_ne(const std::pair< unsigned, unsigned > &p) const
Definition: invariant_set.h:229
invariant_sett::has_eq
bool has_eq(const std::pair< unsigned, unsigned > &p) const
Definition: invariant_set.h:219
numberingt< irep_idt >::number_type
std::size_t number_type
Definition: numbering.h:24
upper_interval
interval_templatet< T > upper_interval(const T &u)
Definition: interval_template.h:253
invariant_sett::make_true
void make_true()
Definition: invariant_set.h:119
codet
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:28
to_constant_expr
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2992
integer2string
const std::string integer2string(const mp_integer &n, unsigned base)
Definition: mp_arith.cpp:103