Skip to content

Commit a4c81ef

Browse files
authored
Merge pull request #5858 from tautschnig/fix-5857
Assignment side effects may require additional temporaries
2 parents c9679ab + a59f36b commit a4c81ef

File tree

5 files changed

+66
-7
lines changed

5 files changed

+66
-7
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_clean_expr.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,8 @@ void goto_convertt::clean_expr(
409409

410410
if(expr.id()==ID_side_effect)
411411
{
412-
remove_side_effect(to_side_effect_expr(expr), dest, mode, result_is_used);
412+
remove_side_effect(
413+
to_side_effect_expr(expr), dest, mode, result_is_used, false);
413414
}
414415
else if(expr.id()==ID_compound_literal)
415416
{
@@ -482,7 +483,7 @@ void goto_convertt::clean_expr_address_of(
482483
}
483484
else if(expr.id() == ID_side_effect)
484485
{
485-
remove_side_effect(to_side_effect_expr(expr), dest, mode, true);
486+
remove_side_effect(to_side_effect_expr(expr), dest, mode, true, true);
486487
}
487488
else
488489
Forall_operands(it, expr)

src/goto-programs/goto_convert_class.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,13 @@ class goto_convertt:public messaget
102102
side_effect_exprt &expr,
103103
goto_programt &dest,
104104
const irep_idt &mode,
105-
bool result_is_used);
105+
bool result_is_used,
106+
bool address_taken);
106107
void remove_assignment(
107108
side_effect_exprt &expr,
108109
goto_programt &dest,
109110
bool result_is_used,
111+
bool address_taken,
110112
const irep_idt &mode);
111113
void remove_pre(
112114
side_effect_exprt &expr,

src/goto-programs/goto_convert_side_effect.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,25 @@ void goto_convertt::remove_assignment(
3838
side_effect_exprt &expr,
3939
goto_programt &dest,
4040
bool result_is_used,
41+
bool address_taken,
4142
const irep_idt &mode)
4243
{
4344
const irep_idt statement=expr.get_statement();
4445

46+
optionalt<exprt> replacement_expr_opt;
47+
4548
if(statement==ID_assign)
4649
{
4750
auto &old_assignment = to_side_effect_expr_assign(expr);
51+
52+
if(result_is_used && !address_taken && needs_cleaning(old_assignment.lhs()))
53+
{
54+
if(!old_assignment.rhs().is_constant())
55+
make_temp_symbol(old_assignment.rhs(), "assign", dest, mode);
56+
57+
replacement_expr_opt = old_assignment.rhs();
58+
}
59+
4860
exprt new_lhs = skip_typecast(old_assignment.lhs());
4961
exprt new_rhs =
5062
typecast_exprt::conditional_cast(old_assignment.rhs(), new_lhs.type());
@@ -113,10 +125,17 @@ void goto_convertt::remove_assignment(
113125
rhs.type() = to_binary_expr(expr).op0().type();
114126
rhs.add_source_location() = expr.source_location();
115127

128+
if(
129+
result_is_used && !address_taken &&
130+
needs_cleaning(to_binary_expr(expr).op0()))
131+
{
132+
make_temp_symbol(rhs, "assign", dest, mode);
133+
replacement_expr_opt = rhs;
134+
}
135+
116136
exprt new_lhs = skip_typecast(to_binary_expr(expr).op0());
117137
rhs = typecast_exprt::conditional_cast(rhs, new_lhs.type());
118138
rhs.add_source_location() = expr.source_location();
119-
120139
code_assignt assignment(new_lhs, rhs);
121140
assignment.add_source_location()=expr.source_location();
122141

@@ -126,7 +145,13 @@ void goto_convertt::remove_assignment(
126145
UNREACHABLE;
127146

128147
// revert assignment in the expression to its LHS
129-
if(result_is_used)
148+
if(replacement_expr_opt.has_value())
149+
{
150+
exprt new_lhs =
151+
typecast_exprt::conditional_cast(*replacement_expr_opt, expr.type());
152+
expr.swap(new_lhs);
153+
}
154+
else if(result_is_used)
130155
{
131156
exprt lhs = to_binary_expr(expr).op0();
132157
// assign_* statements can have an lhs operand with a different type than
@@ -556,7 +581,8 @@ void goto_convertt::remove_side_effect(
556581
side_effect_exprt &expr,
557582
goto_programt &dest,
558583
const irep_idt &mode,
559-
bool result_is_used)
584+
bool result_is_used,
585+
bool address_taken)
560586
{
561587
const irep_idt &statement=expr.get_statement();
562588

@@ -575,7 +601,7 @@ void goto_convertt::remove_side_effect(
575601
statement==ID_assign_ashr ||
576602
statement==ID_assign_shl ||
577603
statement==ID_assign_mod)
578-
remove_assignment(expr, dest, result_is_used, mode);
604+
remove_assignment(expr, dest, result_is_used, address_taken, mode);
579605
else if(statement==ID_postincrement ||
580606
statement==ID_postdecrement)
581607
remove_post(expr, dest, mode, result_is_used);

0 commit comments

Comments
 (0)