Skip to content

Commit f891f37

Browse files
authored
Merge pull request #2168 from JohnDumbell/bugfix/phi_merge_uninitialized
Don't phi-merge uninitialised objects
2 parents 20e7bca + 6faf376 commit f891f37

File tree

15 files changed

+251
-3
lines changed

15 files changed

+251
-3
lines changed
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
public class PhiMergeUninitialized {
2+
3+
public int dynamicAllocationUninitialized(Boolean trigger) {
4+
5+
Ephemeral obj;
6+
if (trigger) {
7+
obj = new Ephemeral(42);
8+
} else {
9+
obj = new Aetherial(20);
10+
}
11+
12+
assert obj.val == 20;
13+
return obj.val;
14+
}
15+
16+
private Ephemeral field;
17+
18+
public int fieldUninitialized(Boolean trigger) {
19+
if (trigger) {
20+
field = new Ephemeral(42);
21+
}
22+
23+
assert field.val == 42;
24+
return field.val;
25+
}
26+
27+
private static Ephemeral staticField;
28+
29+
public int staticFieldUninitialized(Boolean trigger) {
30+
if (trigger) {
31+
staticField = new Ephemeral(42);
32+
} else {
33+
staticField = new Aetherial(76);
34+
}
35+
36+
assert staticField.val == 76;
37+
return staticField.val;
38+
}
39+
40+
class Ephemeral {
41+
Ephemeral(int value) {
42+
val = value;
43+
}
44+
45+
int val;
46+
}
47+
48+
class Aetherial extends Ephemeral {
49+
Aetherial(int value) {
50+
super(value);
51+
}
52+
}
53+
}
54+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
PhiMergeUninitialized.class
3+
--function PhiMergeUninitialized.fieldUninitialized --show-vcc
4+
activate-multi-line-match
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^.*:\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\)
9+
^.*\?\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\s+:
10+
--
11+
These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below
12+
statement:
13+
14+
(guard ? dynamic_object2@3#1 : dynamic_object3@3#0)
15+
16+
Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
PhiMergeUninitialized.class
3+
--function PhiMergeUninitialized.dynamicAllocationUninitialized --show-vcc
4+
activate-multi-line-match
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^.*:\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\)
9+
^.*\?\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\s+:
10+
--
11+
These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below
12+
statement:
13+
14+
(guard ? dynamic_object2@3#1 : dynamic_object3@3#0)
15+
16+
Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
PhiMergeUninitialized.class
3+
--function PhiMergeUninitialized.staticFieldUninitialized --show-vcc
4+
activate-multi-line-match
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^.*:\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\)
9+
^.*\?\s+(dynamic_object|new_tmp)[0-9]+(@[0-9]+)?#0\s+:
10+
--
11+
These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below
12+
statement:
13+
14+
(guard ? dynamic_object2@3#1 : dynamic_object3@3#0)
15+
16+
Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
test.c
3+
--function dynamicAllocationUninitialized --show-vcc
4+
activate-multi-line-match
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^.*:\s+dynamic_object[0-9]+(@[0-9]+)?#0\)
9+
^.*\?\s+dynamic_object[0-9]+(@[0-9]+)?#0\s+:
10+
--
11+
These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below
12+
statement:
13+
14+
(guard ? dynamic_object2@3#1 : dynamic_object3@3#0)
15+
16+
Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
test.c
3+
--function globalUninitialized --show-vcc
4+
activate-multi-line-match
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^.*:\s+global(@[0-9]+)?#0\)
9+
^.*\?\s+global(@[0-9]+)?#0\s+:
10+
--
11+
These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below
12+
statement:
13+
14+
(guard ? global#1 : global#0)
15+
16+
Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
test.c
3+
--function localUninitialized --show-vcc
4+
activate-multi-line-match
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^.*:\s+local(@[0-9]+)?#0\)
9+
^.*\?\s+local(@[0-9]+)?#0\s+:
10+
--
11+
These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below
12+
statement:
13+
14+
(guard ? local#1 : local#0)
15+
16+
Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
test.c
3+
--function staticLocalUninitialized --show-vcc
4+
activate-multi-line-match
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^.*:\s+staticLocal(@[0-9]+)?#0\)
9+
^.*\?\s+staticLocal(@[0-9]+)?#0\s+:
10+
--
11+
These regexes are making sure that a variable of generation 0 dosen't appear in a phi merge, so the below
12+
statement:
13+
14+
(guard ? staticLocal#1 : dynamic_object#0)
15+
16+
Should not appear. First regex deals with when the gen zero is the latter position, second when it's in the former.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void dynamicAllocationUninitialized(int trigger)
5+
{
6+
int *obj;
7+
if(trigger)
8+
{
9+
obj = (int *)malloc(sizeof(int));
10+
*obj = 42;
11+
}
12+
else
13+
{
14+
obj = (int *)malloc(sizeof(int));
15+
*obj = 76;
16+
}
17+
18+
assert(*obj == 42);
19+
}
20+
21+
int global;
22+
void globalUninitialized(int trigger)
23+
{
24+
if(trigger)
25+
{
26+
global = 44;
27+
}
28+
else
29+
{
30+
global = 20;
31+
}
32+
33+
assert(global == 44);
34+
}
35+
36+
void staticLocalUninitialized(int trigger)
37+
{
38+
static int staticLocal;
39+
if(trigger)
40+
{
41+
staticLocal = 43;
42+
}
43+
44+
assert(staticLocal == 43);
45+
}
46+
47+
void localUninitialized(int trigger)
48+
{
49+
int local;
50+
if(trigger)
51+
{
52+
local = 24;
53+
}
54+
55+
assert(local == 24);
56+
}

regression/test.pl

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ ($$$$$$$$$)
174174
binmode $fh;
175175
my $whole_file = <$fh>;
176176
$whole_file =~ s/\r\n/\n/g;
177-
my $is_match = $whole_file =~ /$result/;
177+
my $is_match = $whole_file =~ /$result/m;
178178
$r = ($included ? !$is_match : $is_match);
179179
}
180180
else

src/goto-symex/goto_symex.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@ void goto_symext::do_simplify(exprt &expr)
2222
simplify(expr, ns);
2323
}
2424

25+
nondet_symbol_exprt goto_symext::build_symex_nondet(typet &type)
26+
{
27+
irep_idt identifier = "symex::nondet" + std::to_string(nondet_count++);
28+
nondet_symbol_exprt new_expr(identifier, type);
29+
return new_expr;
30+
}
31+
2532
void goto_symext::replace_nondet(exprt &expr)
2633
{
2734
if(expr.id()==ID_side_effect &&
2835
expr.get(ID_statement)==ID_nondet)
2936
{
30-
irep_idt identifier="symex::nondet"+std::to_string(nondet_count++);
31-
nondet_symbol_exprt new_expr(identifier, expr.type());
37+
nondet_symbol_exprt new_expr = build_symex_nondet(expr.type());
3238
new_expr.add_source_location()=expr.source_location();
3339
expr.swap(new_expr);
3440
}

src/goto-symex/goto_symex.h

+2
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,8 @@ class goto_symext
368368
exprt &code,
369369
const irep_idt &identifier);
370370

371+
nondet_symbol_exprt build_symex_nondet(typet &type);
372+
371373
// exceptions
372374
void symex_throw(statet &);
373375
void symex_catch(statet &);

src/goto-symex/symex_builtin_functions.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ void goto_symext::symex_allocate(
184184
else
185185
throw "failed to zero initialize dynamic object";
186186
}
187+
else
188+
{
189+
exprt nondet = build_symex_nondet(object_type);
190+
code_assignt assignment(value_symbol.symbol_expr(), nondet);
191+
symex_assign(state, assignment);
192+
}
187193

188194
exprt rhs;
189195

src/goto-symex/symex_goto.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -443,10 +443,22 @@ void goto_symext::phi_function(
443443

444444
exprt rhs;
445445

446+
// Don't add a conditional to the assignment when:
447+
// 1. Either guard is false, so we can't follow that branch.
448+
// 2. Either identifier is of generation zero, and so hasn't been
449+
// initialized and therefor an invalid target.
446450
if(dest_state.guard.is_false())
447451
rhs=goto_state_rhs;
448452
else if(goto_state.guard.is_false())
449453
rhs=dest_state_rhs;
454+
else if(goto_state.level2_current_count(l1_identifier) == 0)
455+
{
456+
rhs = dest_state_rhs;
457+
}
458+
else if(dest_state.level2.current_count(l1_identifier) == 0)
459+
{
460+
rhs = goto_state_rhs;
461+
}
450462
else
451463
{
452464
rhs=if_exprt(diff_guard.as_expr(), goto_state_rhs, dest_state_rhs);

0 commit comments

Comments
 (0)