Skip to content

Commit 29266a0

Browse files
committed
Assignment side effects may require additional temporaries
An assignment may invalidate pointers used in the left-hand side. In case the result of the assignment is used, we therefore cannot re-use the left-hand side to represent the result. Instead, introduce temporaries as needed to store the right-hand side value, and use the temporary to represent the result. Fixes: #5857
1 parent 308cc0a commit 29266a0

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

regression/cbmc/Sideeffects8/main.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
struct A
5+
{
6+
struct A *p;
7+
};
8+
9+
int main(void)
10+
{
11+
struct A x = {&x};
12+
struct A *r = x.p->p = NULL;
13+
assert(r == NULL);
14+
15+
struct A arr[2] = {arr, 0};
16+
r = arr[0].p->p += 1;
17+
assert(r == &arr[1]);
18+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--pointer-check
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
Invariant check failed
9+
^warning: ignoring
10+
--
11+
Assignments can affect dereferences occuring with the LHS, and thus may require
12+
introducing temporaries.

src/goto-programs/goto_convert_side_effect.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,20 @@ void goto_convertt::remove_assignment(
4242
{
4343
const irep_idt statement=expr.get_statement();
4444

45+
optionalt<exprt> replacement_expr_opt;
46+
4547
if(statement==ID_assign)
4648
{
4749
auto &old_assignment = to_side_effect_expr_assign(expr);
50+
51+
if(result_is_used && needs_cleaning(old_assignment.lhs()))
52+
{
53+
if(!old_assignment.rhs().is_constant())
54+
make_temp_symbol(old_assignment.rhs(), "assign", dest, mode);
55+
56+
replacement_expr_opt = old_assignment.rhs();
57+
}
58+
4859
exprt new_lhs = skip_typecast(old_assignment.lhs());
4960
exprt new_rhs =
5061
typecast_exprt::conditional_cast(old_assignment.rhs(), new_lhs.type());
@@ -113,6 +124,12 @@ void goto_convertt::remove_assignment(
113124
rhs.type() = to_binary_expr(expr).op0().type();
114125
rhs.add_source_location() = expr.source_location();
115126

127+
if(result_is_used && needs_cleaning(to_binary_expr(expr).op0()))
128+
{
129+
make_temp_symbol(rhs, "assign", dest, mode);
130+
replacement_expr_opt = rhs;
131+
}
132+
116133
exprt new_lhs = skip_typecast(to_binary_expr(expr).op0());
117134
rhs = typecast_exprt::conditional_cast(rhs, new_lhs.type());
118135
rhs.add_source_location() = expr.source_location();
@@ -128,7 +145,7 @@ void goto_convertt::remove_assignment(
128145
// revert assignment in the expression to its LHS
129146
if(result_is_used)
130147
{
131-
exprt lhs = to_binary_expr(expr).op0();
148+
exprt lhs = replacement_expr_opt.value_or(to_binary_expr(expr).op0());
132149
// assign_* statements can have an lhs operand with a different type than
133150
// that of the overall expression, because of integer promotion (which may
134151
// have introduced casts to the lhs).

0 commit comments

Comments
 (0)