CBMC
overflow_instrumenter.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Loop Acceleration
4 
5 Author: Matt Lewis
6 
7 \*******************************************************************/
8 
11 
12 #include "overflow_instrumenter.h"
13 
14 #include <util/arith_tools.h>
15 #include <util/bitvector_expr.h>
16 
18 
19 #include "util.h"
20 
21 /*
22  * This code is copied wholesale from analyses/goto_check.cpp.
23  */
24 
25 
27 {
29  program.instructions.begin(),
31 
33  checked.clear();
34 
36  {
38  }
39 }
40 
44 {
45  if(checked.find(t->location_number)!=checked.end())
46  {
47  return;
48  }
49 
50  if(t->is_assign())
51  {
52  if(t->assign_lhs() == overflow_var)
53  {
54  return;
55  }
56 
57  add_overflow_checks(t, t->assign_lhs_nonconst(), added);
58  add_overflow_checks(t, t->assign_rhs_nonconst(), added);
59  }
60 
61  if(t->has_condition())
62  add_overflow_checks(t, t->condition(), added);
63 
64  checked.insert(t->location_number);
65 }
66 
69 {
71  add_overflow_checks(t, ignore);
72 }
73 
76  const exprt &expr,
78 {
79  exprt overflow;
80  overflow_expr(expr, overflow);
81 
82  if(overflow!=false_exprt())
83  {
84  accumulate_overflow(t, overflow, added);
85  }
86 }
87 
89  const exprt &expr,
90  expr_sett &cases)
91 {
92  for(const auto &op : expr.operands())
93  {
94  overflow_expr(op, cases);
95  }
96 
97  const typet &type = expr.type();
98 
99  if(expr.id()==ID_typecast)
100  {
101  const auto &typecast_expr = to_typecast_expr(expr);
102 
103  if(typecast_expr.op().is_constant())
104  return;
105 
106  const typet &old_type = typecast_expr.op().type();
107  const std::size_t new_width = to_bitvector_type(expr.type()).get_width();
108  const std::size_t old_width = to_bitvector_type(old_type).get_width();
109 
110  if(type.id()==ID_signedbv)
111  {
112  if(old_type.id()==ID_signedbv)
113  {
114  // signed -> signed
115  if(new_width >= old_width)
116  {
117  // Always safe.
118  return;
119  }
120 
121  cases.insert(binary_relation_exprt(
122  typecast_expr.op(),
123  ID_gt,
124  from_integer(power(2, new_width - 1) - 1, old_type)));
125 
126  cases.insert(binary_relation_exprt(
127  typecast_expr.op(),
128  ID_lt,
129  from_integer(-power(2, new_width - 1), old_type)));
130  }
131  else if(old_type.id()==ID_unsignedbv)
132  {
133  // unsigned -> signed
134  if(new_width >= old_width + 1)
135  {
136  // Always safe.
137  return;
138  }
139 
140  cases.insert(binary_relation_exprt(
141  typecast_expr.op(),
142  ID_gt,
143  from_integer(power(2, new_width - 1) - 1, old_type)));
144  }
145  }
146  else if(type.id()==ID_unsignedbv)
147  {
148  if(old_type.id()==ID_signedbv)
149  {
150  // signed -> unsigned
151  cases.insert(binary_relation_exprt(
152  typecast_expr.op(), ID_lt, from_integer(0, old_type)));
153  if(new_width < old_width - 1)
154  {
155  // Need to check for overflow as well as signedness.
156  cases.insert(binary_relation_exprt(
157  typecast_expr.op(),
158  ID_gt,
159  from_integer(power(2, new_width - 1) - 1, old_type)));
160  }
161  }
162  else if(old_type.id()==ID_unsignedbv)
163  {
164  // unsigned -> unsigned
165  if(new_width>=old_width)
166  {
167  // Always safe.
168  return;
169  }
170 
171  cases.insert(binary_relation_exprt(
172  typecast_expr.op(),
173  ID_gt,
174  from_integer(power(2, new_width - 1) - 1, old_type)));
175  }
176  }
177  }
178  else if(expr.id()==ID_div)
179  {
180  const auto &div_expr = to_div_expr(expr);
181 
182  // Undefined for signed INT_MIN / -1
183  if(type.id()==ID_signedbv)
184  {
185  equal_exprt int_min_eq(
186  div_expr.dividend(), to_signedbv_type(type).smallest_expr());
187  equal_exprt minus_one_eq(div_expr.divisor(), from_integer(-1, type));
188 
189  cases.insert(and_exprt(int_min_eq, minus_one_eq));
190  }
191  }
192  else if(expr.id()==ID_unary_minus)
193  {
194  if(type.id()==ID_signedbv)
195  {
196  // Overflow on unary- can only happen with the smallest
197  // representable number.
198  cases.insert(equal_exprt(
199  to_unary_minus_expr(expr).op(),
200  to_signedbv_type(type).smallest_expr()));
201  }
202  }
203  else if(expr.id()==ID_plus ||
204  expr.id()==ID_minus ||
205  expr.id()==ID_mult)
206  {
207  // A generic arithmetic operation.
208  // The overflow checks are binary.
209  for(std::size_t i = 1; i < expr.operands().size(); i++)
210  {
211  exprt tmp;
212 
213  if(i == 1)
214  {
215  tmp = to_multi_ary_expr(expr).op0();
216  }
217  else
218  {
219  tmp = expr;
220  tmp.operands().resize(i);
221  }
222 
223  binary_overflow_exprt overflow{tmp, expr.id(), expr.operands()[i]};
224 
225  fix_types(overflow);
226 
227  cases.insert(overflow);
228  }
229  }
230 }
231 
233 {
234  expr_sett cases;
235 
236  overflow_expr(expr, cases);
237 
238  overflow=false_exprt();
239 
240  for(expr_sett::iterator it=cases.begin();
241  it!=cases.end();
242  ++it)
243  {
244  if(overflow==false_exprt())
245  {
246  overflow=*it;
247  }
248  else
249  {
250  overflow=or_exprt(overflow, *it);
251  }
252  }
253 }
254 
256 {
257  typet &t1=overflow.op0().type();
258  typet &t2=overflow.op1().type();
259  const typet &t=join_types(t1, t2);
260 
261  if(t1!=t)
262  {
263  overflow.op0()=typecast_exprt(overflow.op0(), t);
264  }
265 
266  if(t2!=t)
267  {
268  overflow.op1()=typecast_exprt(overflow.op1(), t);
269  }
270 }
271 
274  const exprt &expr,
276 {
278  t,
280  assignment->swap(*t);
281 
282  added.push_back(assignment);
283 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
API to expression classes for bitvectors.
const signedbv_typet & to_signedbv_type(const typet &type)
Cast a typet to a signedbv_typet.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
Boolean AND.
Definition: std_expr.h:2120
A base class for binary expressions.
Definition: std_expr.h:638
exprt & op1()
Definition: expr.h:136
exprt & op0()
Definition: expr.h:133
A Boolean expression returning true, iff operation kind would result in an overflow when applied to o...
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:762
std::size_t get_width() const
Definition: std_types.h:920
A goto_instruction_codet representing an assignment in the program.
Equality.
Definition: std_expr.h:1361
Base class for all expressions.
Definition: expr.h:56
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
The Boolean constant false.
Definition: std_expr.h:3064
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
instructionst::iterator targett
Definition: goto_program.h:614
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
targett insert_after(const_targett target)
Insertion after the instruction pointed-to by the given instruction iterator target.
Definition: goto_program.h:708
void compute_location_numbers(unsigned &nr)
Compute location numbers.
Definition: goto_program.h:766
targett insert_before(const_targett target)
Insertion before the instruction pointed-to by the given instruction iterator target.
Definition: goto_program.h:692
std::list< targett > targetst
Definition: goto_program.h:616
const irep_idt & id() const
Definition: irep.h:384
exprt & op0()
Definition: std_expr.h:932
Boolean OR.
Definition: std_expr.h:2228
std::set< unsigned > checked
void fix_types(binary_exprt &overflow)
void accumulate_overflow(goto_programt::targett t, const exprt &expr, goto_programt::targetst &added)
void overflow_expr(const exprt &expr, expr_sett &cases)
Semantic type conversion.
Definition: std_expr.h:2068
The type of an expression, extends irept.
Definition: type.h:29
std::unordered_set< exprt, irep_hash > expr_sett
Concrete Goto Program.
#define Forall_goto_program_instructions(it, program)
Loop Acceleration.
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2102
const unary_minus_exprt & to_unary_minus_expr(const exprt &expr)
Cast an exprt to a unary_minus_exprt.
Definition: std_expr.h:514
const div_exprt & to_div_expr(const exprt &expr)
Cast an exprt to a div_exprt.
Definition: std_expr.h:1201
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition: std_expr.h:987
typet join_types(const typet &t1, const typet &t2)
Return the smallest type that both t1 and t2 can be cast to without losing information.
Definition: util.cpp:70
Loop Acceleration.