CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
symex_assign.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Symbolic Execution
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "symex_assign.h"
13
14#include <util/byte_operators.h>
15#include <util/expr_util.h>
16#include <util/pointer_expr.h>
17#include <util/range.h>
18
19#include "expr_skeleton.h"
20#include "goto_symex_state.h"
21#include "symex_config.h"
22
23// We can either use with_exprt or update_exprt when building expressions that
24// modify components of an array or a struct. Set USE_UPDATE to use
25// update_exprt.
26// #define USE_UPDATE
27
28constexpr bool use_update()
29{
30#ifdef USE_UPDATE
31 return true;
32#else
33 return false;
34#endif
35}
36
42{
44 {
45 if(
46 const auto &index =
48 {
49 if(index->array().id() == ID_string_constant && index->index().is_zero())
50 {
51 return true;
52 }
53 }
54 }
55 return false;
56}
57
59 const exprt &lhs,
60 const expr_skeletont &full_lhs,
61 const exprt &rhs,
63{
64 if(is_ssa_expr(lhs))
65 {
66 assign_symbol(to_ssa_expr(lhs), full_lhs, rhs, guard);
67
68 // Allocate shadow memory
69 if(shadow_memory.has_value())
70 {
73 {
74 shadow_memory->symex_field_static_init_string_constant(
75 state, to_ssa_expr(lhs), rhs);
76 }
77 else
78 {
79 shadow_memory->symex_field_static_init(state, to_ssa_expr(lhs));
80 }
81 }
82 }
83 else if(lhs.id() == ID_index)
85 else if(lhs.id()==ID_member)
86 {
87 const typet &type = to_member_expr(lhs).struct_op().type();
88 if(type.id() == ID_struct || type.id() == ID_struct_tag)
89 {
91 to_member_expr(lhs), full_lhs, rhs, guard);
92 }
93 else if(type.id() == ID_union || type.id() == ID_union_tag)
94 {
95 // should have been replaced by byte_extract
97 "assign_rec: unexpected assignment to union member");
98 }
99 else
101 "assign_rec: unexpected assignment to member of '" + type.id_string() +
102 "'");
103 }
104 else if(lhs.id()==ID_if)
105 assign_if(to_if_expr(lhs), full_lhs, rhs, guard);
106 else if(lhs.id()==ID_typecast)
107 assign_typecast(to_typecast_expr(lhs), full_lhs, rhs, guard);
109 {
110 // ignore
111 }
112 else if(lhs.id()==ID_byte_extract_little_endian ||
114 {
115 assign_byte_extract(to_byte_extract_expr(lhs), full_lhs, rhs, guard);
116 }
117 else if(lhs.id() == ID_complex_real)
118 {
119 // this is stuff like __real__ x = 1;
121
123
126
127 assign_rec(complex_real_expr.op(), full_lhs, new_rhs, guard);
128 }
129 else if(lhs.id() == ID_complex_imag)
130 {
132
134
137
138 assign_rec(complex_imag_expr.op(), full_lhs, new_rhs, guard);
139 }
140 else
142 "assignment to '" + lhs.id_string() + "' not handled");
143}
144
153
166 const ssa_exprt &lhs, // L1
167 const expr_skeletont &full_lhs,
168 const struct_exprt &rhs,
169 const exprt::operandst &guard)
170{
171 const auto &components =
172 lhs.type().id() == ID_struct_tag
173 ? ns.follow_tag(to_struct_tag_type(lhs.type())).components()
174 : to_struct_type(lhs.type()).components();
175 PRECONDITION(rhs.operands().size() == components.size());
176
177 for(const auto &comp_rhs : make_range(components).zip(rhs.operands()))
178 {
179 const auto &comp = comp_rhs.first;
181 ns, state, member_exprt{lhs, comp.get_name(), comp.type()}, true);
182 INVARIANT(
183 lhs_field.id() == ID_symbol,
184 "member of symbol should be susceptible to field-sensitivity");
185
186 assign_symbol(to_ssa_expr(lhs_field), full_lhs, comp_rhs.second, guard);
187 }
188}
189
191 const ssa_exprt &lhs, // L1
192 const expr_skeletont &full_lhs,
193 const exprt &rhs,
194 const exprt::operandst &guard)
195{
196 exprt l2_rhs =
197 state
198 .rename(
199 // put assignment guard into the rhs
200 guard.empty()
201 ? rhs
202 : static_cast<exprt>(if_exprt{conjunction(guard), rhs, lhs}),
203 ns)
204 .get();
205
206 assignmentt assignment{lhs, full_lhs, l2_rhs};
207
208 if(symex_config.simplify_opt)
209 assignment.rhs = simplify_expr(std::move(assignment.rhs), ns);
210
211 const ssa_exprt l2_lhs = state
212 .assignment(
213 assignment.lhs,
214 assignment.rhs,
215 ns,
216 symex_config.simplify_opt,
217 symex_config.constant_propagation,
218 symex_config.allow_pointer_unsoundness)
219 .get();
220
221 state.record_events.push(false);
222 // Note any other symbols mentioned in the skeleton are rvalues -- for example
223 // array indices -- and were renamed to L2 at the start of
224 // goto_symext::symex_assign.
225 const exprt l2_full_lhs = assignment.original_lhs_skeleton.apply(l2_lhs);
226 if(symex_config.run_validation_checks)
227 {
228 INVARIANT(
229 !check_renaming(l2_full_lhs), "l2_full_lhs should be renamed to L2");
230 }
231 state.record_events.pop();
232
234 ns.lookup(l2_lhs.get_object_name()).is_auxiliary &&
235 id2string(l2_lhs.get_object_name()).find(SHADOW_MEMORY_SYMBOL_PREFIX) !=
236 std::string::npos
239
242 l2_lhs,
245 assignment.rhs,
248
249 const ssa_exprt &l1_lhs = assignment.lhs;
251 {
252 // Split composite symbol lhs into its components
254 ns,
255 state,
256 l1_lhs,
257 assignment.rhs,
258 target,
259 symex_config.allow_pointer_unsoundness);
260 }
261}
262
264 const ssa_exprt &lhs, // L1
265 const expr_skeletont &full_lhs,
266 const exprt &rhs,
267 const exprt::operandst &guard)
268{
269 // Shortcut the common case of a whole-struct initializer:
270 if(rhs.id() == ID_struct)
271 assign_from_struct(lhs, full_lhs, to_struct_expr(rhs), guard);
272 else
273 assign_non_struct_symbol(lhs, full_lhs, rhs, guard);
274}
275
277 const typecast_exprt &lhs,
278 const expr_skeletont &full_lhs,
279 const exprt &rhs,
281{
282 // these may come from dereferencing on the lhs
285 full_lhs.compose(expr_skeletont::remove_op0(lhs));
287}
288
289template <bool use_update>
291 const index_exprt &lhs,
292 const expr_skeletont &full_lhs,
293 const exprt &rhs,
295{
296 const exprt &lhs_array=lhs.array();
297 const exprt &lhs_index=lhs.index();
298 const typet &lhs_index_type = lhs_array.type();
299
301
302 if(use_update)
303 {
304 // turn
305 // a[i]=e
306 // into
307 // a'==UPDATE(a, [i], e)
310 full_lhs.compose(expr_skeletont::remove_op0(lhs));
312 }
313 else
314 {
315 // turn
316 // a[i]=e
317 // into
318 // a'==a WITH [i:=e]
321 full_lhs.compose(expr_skeletont::remove_op0(lhs));
323 }
324}
325
326template <bool use_update>
328 const member_exprt &lhs,
329 const expr_skeletont &full_lhs,
330 const exprt &rhs,
332{
333 // Symbolic execution of a struct member assignment.
334
335 // lhs must be member operand, which
336 // takes one operand, which must be a structure.
337
338 exprt lhs_struct = lhs.op();
339
340 // typecasts involved? C++ does that for inheritance.
341 if(lhs_struct.id()==ID_typecast)
342 {
344 {
345 // ignore, and give up
346 return;
347 }
348 else
349 {
350 // remove the type cast, we assume that the member is there
352
353 if(tmp.type().id() == ID_struct || tmp.type().id() == ID_struct_tag)
355 else
356 return; // ignore and give up
357 }
358 }
359
360 const irep_idt &component_name=lhs.get_component_name();
361
362 if(use_update)
363 {
364 // turn
365 // a.c=e
366 // into
367 // a'==UPDATE(a, .c, e)
368 const update_exprt new_rhs{
369 lhs_struct, member_designatort(component_name), rhs};
371 full_lhs.compose(expr_skeletont::remove_op0(lhs));
373 }
374 else
375 {
376 // turn
377 // a.c=e
378 // into
379 // a'==a WITH [c:=e]
380
382 new_rhs.where().set(ID_component_name, component_name);
384 full_lhs.compose(expr_skeletont::remove_op0(lhs));
386 }
387}
388
390 const if_exprt &lhs,
391 const expr_skeletont &full_lhs,
392 const exprt &rhs,
394{
395 // we have (c?a:b)=e;
396
397 guard.push_back(lhs.cond());
398 assign_rec(lhs.true_case(), full_lhs, rhs, guard);
399 guard.pop_back();
400
401 guard.push_back(not_exprt(lhs.cond()));
402 assign_rec(lhs.false_case(), full_lhs, rhs, guard);
403 guard.pop_back();
404}
405
407 const byte_extract_exprt &lhs,
408 const expr_skeletont &full_lhs,
409 const exprt &rhs,
411{
412 // we have byte_extract_X(object, offset)=value
413 // turn into object=byte_update_X(object, offset, value)
414
418 else if(lhs.id()==ID_byte_extract_big_endian)
420 else
422
424 byte_update_id, lhs.op(), lhs.offset(), rhs, lhs.get_bits_per_byte()};
426 full_lhs.compose(expr_skeletont::remove_op0(lhs));
428}
static irep_idt byte_update_id()
Expression classes for byte-level operators.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
static exprt guard(const exprt::operandst &guards, exprt cond)
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Expression of type type extracted from some object op starting at position offset (given in number of...
std::size_t get_bits_per_byte() const
Expression corresponding to op() where the bytes starting at position offset (given in number of byte...
Complex constructor from a pair of numbers.
Definition std_expr.h:1916
Imaginary part of the expression describing a complex number.
Definition std_expr.h:2027
Real part of the expression describing a complex number.
Definition std_expr.h:1984
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Expression in which some part is missing and can be substituted for another expression.
expr_skeletont compose(expr_skeletont other) const
Replace the missing part of the current skeleton by another skeleton, ending in a bigger skeleton cor...
static expr_skeletont remove_op0(exprt e)
Create a skeleton by removing the first operand of e.
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
exprt apply(const namespacet &ns, goto_symex_statet &state, exprt expr, bool write) const
Turn an expression expr into a field-sensitive SSA expression.
void field_assignments(const namespacet &ns, goto_symex_statet &state, const ssa_exprt &lhs, const exprt &rhs, symex_targett &target, bool allow_pointer_unsoundness) const
Assign to the individual fields of a non-expanded symbol lhs.
bool is_divisible(const ssa_exprt &expr, bool disjoined_fields_only) const
Determine whether expr would translate to an atomic SSA expression (returns false) or a composite obj...
guardt guard
Definition goto_state.h:58
std::stack< bool > record_events
renamedt< ssa_exprt, L2 > assignment(ssa_exprt lhs, const exprt &rhs, const namespacet &ns, bool rhs_is_simplified, bool record_value, bool allow_pointer_unsoundness=false)
renamedt< exprt, level > rename(exprt expr, const namespacet &ns)
Rewrites symbol expressions in exprt, applying a suffix to each symbol reflecting its most recent ver...
static bool is_read_only_object(const exprt &lvalue)
Returns true if lvalue is a read-only object, such as the null object.
field_sensitivityt field_sensitivity
symex_targett::sourcet source
exprt as_expr() const
Definition guard_expr.h:46
The trinary if-then-else operator.
Definition std_expr.h:2497
exprt & cond()
Definition std_expr.h:2514
exprt & false_case()
Definition std_expr.h:2534
exprt & true_case()
Definition std_expr.h:2524
Array index operator.
Definition std_expr.h:1470
exprt & index()
Definition std_expr.h:1510
exprt & array()
Definition std_expr.h:1500
const std::string & id_string() const
Definition irep.h:391
const irep_idt & id() const
Definition irep.h:388
Extract member of struct or union.
Definition std_expr.h:2971
irep_idt get_component_name() const
Definition std_expr.h:2993
Boolean negation.
Definition std_expr.h:2454
Expression providing an SSA-renamed symbol of expressions.
Definition ssa_expr.h:17
Struct constructor from list of elements.
Definition std_expr.h:1877
void assign_byte_extract(const byte_extract_exprt &lhs, const expr_skeletont &full_lhs, const exprt &rhs, exprt::operandst &guard)
void assign_if(const if_exprt &lhs, const expr_skeletont &full_lhs, const exprt &rhs, exprt::operandst &guard)
const symex_configt & symex_config
void assign_non_struct_symbol(const ssa_exprt &lhs, const expr_skeletont &full_lhs, const exprt &rhs, const exprt::operandst &guard)
goto_symex_statet & state
void assign_array(const index_exprt &lhs, const expr_skeletont &full_lhs, const exprt &rhs, exprt::operandst &guard)
symex_targett & target
void assign_rec(const exprt &lhs, const expr_skeletont &full_lhs, const exprt &rhs, exprt::operandst &guard)
void assign_symbol(const ssa_exprt &lhs, const expr_skeletont &full_lhs, const exprt &rhs, const exprt::operandst &guard)
Record the assignment of value rhs to variable lhs in state and add the equation to target: lhs#{n+1}...
void assign_struct_member(const member_exprt &lhs, const expr_skeletont &full_lhs, const exprt &rhs, exprt::operandst &guard)
symex_targett::assignment_typet assignment_type
const namespacet & ns
void assign_from_struct(const ssa_exprt &lhs, const expr_skeletont &full_lhs, const struct_exprt &rhs, const exprt::operandst &guard)
Assign a struct expression to a symbol.
void assign_typecast(const typecast_exprt &lhs, const expr_skeletont &full_lhs, const exprt &rhs, exprt::operandst &guard)
std::optional< shadow_memoryt > shadow_memory
virtual void assignment(const exprt &guard, const ssa_exprt &ssa_lhs, const exprt &ssa_full_lhs, const exprt &original_full_lhs, const exprt &ssa_rhs, const sourcet &source, assignment_typet assignment_type)=0
Write to a local variable.
Semantic type conversion.
Definition std_expr.h:2073
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2081
The type of an expression, extends irept.
Definition type.h:29
const exprt & op() const
Definition std_expr.h:391
Thrown when we encounter an instruction, parameters to an instruction etc.
Operator to update elements in structs and arrays.
Definition std_expr.h:2782
Operator to update elements in structs and arrays.
Definition std_expr.h:2598
Expression skeleton.
exprt make_and(exprt a, exprt b)
Conjunction of two expressions.
Deprecated expression utility functions.
Symbolic Execution.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
API to expression classes for Pointers.
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition range.h:522
exprt get_original_name(exprt expr)
Undo all levels of renaming.
bool check_renaming(const typet &type)
Check that type is correctly renamed to level 2 and return true in case an error is detected.
#define SHADOW_MEMORY_SYMBOL_PREFIX
exprt simplify_expr(exprt src, const namespacet &ns)
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
#define PRECONDITION(CONDITION)
Definition invariant.h:463
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
bool is_ssa_expr(const exprt &expr)
Definition ssa_expr.h:125
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
Definition ssa_expr.h:145
exprt conjunction(const exprt::operandst &op)
1) generates a conjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition std_expr.cpp:83
const struct_exprt & to_struct_expr(const exprt &expr)
Cast an exprt to a struct_exprt.
Definition std_expr.h:1900
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2577
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
const complex_imag_exprt & to_complex_imag_expr(const exprt &expr)
Cast an exprt to a complex_imag_exprt.
Definition std_expr.h:2053
const complex_real_exprt & to_complex_real_expr(const exprt &expr)
Cast an exprt to a complex_real_exprt.
Definition std_expr.h:2010
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
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition std_types.h:1158
Assignment from the rhs value to the lhs variable.
ssa_exprt lhs
expr_skeletont original_lhs_skeleton
Skeleton to reconstruct the original lhs in the assignment.
constexpr bool use_update()
static bool is_string_constant_initialization(const exprt &rhs)
Determine whether the RHS expression is a string constant initialization.
Symbolic Execution of assignments.
Symbolic Execution.