Skip to content

Commit 589116d

Browse files
authored
Merge pull request #4343 from smowton/smowton/feature/explicily-initialise-externs
Fix symex of functions that may throw
2 parents 92a9401 + d341910 commit 589116d

File tree

7 files changed

+82
-36
lines changed

7 files changed

+82
-36
lines changed
Binary file not shown.
Binary file not shown.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
public class Test {
2+
3+
public static Test f(boolean unknown) throws Exception {
4+
5+
if(unknown)
6+
throw new Exception();
7+
else
8+
return new Test();
9+
10+
}
11+
12+
public static void main(boolean unknown) {
13+
14+
Sub s = new Sub(); // Make sure Sub is loaded
15+
int x = 0;
16+
17+
// The routine below is repeated twice because historically symex could
18+
// behave differently the first and second times a may-throw function was
19+
// called.
20+
21+
try {
22+
Test t1 = f(unknown);
23+
t1.f();
24+
x += t1.g();
25+
}
26+
catch(Exception e) { }
27+
28+
try {
29+
Test t2 = f(unknown);
30+
t2.f();
31+
x += t2.g();
32+
}
33+
catch(Exception e) { }
34+
35+
assert x == 10;
36+
37+
}
38+
39+
public void f() { }
40+
public int g() { return 5; }
41+
42+
}
43+
44+
class Sub extends Test {
45+
46+
public void f() { }
47+
public int g() { return 0; }
48+
49+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CORE
2+
Test.class
3+
--function Test.main --show-vcc
4+
java::Test\.main:\(Z\)V::14::t1!0@1#\d+ = address_of\(symex_dynamic::dynamic_object\d+\)
5+
java::Test\.main:\(Z\)V::9::x!0@1#\d+ = 5 \+ java::Test\.main:\(Z\)V::9::x!0@1#\d+
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
return_value!0#0
10+
java::Sub\.g:\(\)
11+
--
12+
This checks that when a function may throw, we can nonetheless constant-propagate
13+
and populate the value-set for the normal-return path. In particular we don't
14+
expect to see any reference to a zero-generation return value (indicating
15+
reading the return-value when not defined), nor do we expect to see any code
16+
from the Sub class, which is not accessible and can only be reached when
17+
constant propagation has lost information to the point we're not sure which type
18+
virtual calls against Test may find.

src/goto-symex/symex_dead.cpp

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,13 @@ void goto_symext::symex_dead(statet &state)
2222
const code_deadt &code = instruction.get_dead();
2323

2424
ssa_exprt ssa = state.rename_ssa<L1>(ssa_exprt{code.symbol()}, ns);
25-
26-
// in case of pointers, put something into the value set
27-
if(code.symbol().type().id() == ID_pointer)
28-
{
29-
exprt rhs;
30-
if(auto failed = get_failed_symbol(to_symbol_expr(code.symbol()), ns))
31-
rhs = address_of_exprt(*failed, to_pointer_type(code.symbol().type()));
32-
else
33-
rhs=exprt(ID_invalid);
34-
35-
const exprt l1_rhs = state.rename<L1>(std::move(rhs), ns);
36-
state.value_set.assign(ssa, l1_rhs, ns, true, false);
37-
}
38-
3925
const irep_idt &l1_identifier = ssa.get_identifier();
4026

4127
// we cannot remove the object from the L1 renaming map, because L1 renaming
4228
// information is not local to a path, but removing it from the propagation
43-
// map is safe as 1) it is local to a path and 2) this instance can no longer
44-
// appear
29+
// map and value-set is safe as 1) it is local to a path and 2) this instance
30+
// can no longer appear
31+
state.value_set.values.erase(l1_identifier);
4532
state.propagation.erase(l1_identifier);
4633
// increment the L2 index to ensure a merge on join points will propagate the
4734
// value for branches that are still live

src/goto-symex/symex_goto.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -520,14 +520,10 @@ static void merge_names(
520520
rhs = goto_state_rhs;
521521
else if(goto_state.guard.is_false())
522522
rhs = dest_state_rhs;
523-
else if(goto_count == 0 && !symbol.is_static_lifetime)
524-
{
523+
else if(goto_count == 0)
525524
rhs = dest_state_rhs;
526-
}
527-
else if(dest_count == 0 && !symbol.is_static_lifetime)
528-
{
525+
else if(dest_count == 0)
529526
rhs = goto_state_rhs;
530-
}
531527
else
532528
{
533529
rhs = if_exprt(diff_guard.as_expr(), goto_state_rhs, dest_state_rhs);

src/linking/static_lifetime_init.cpp

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,6 @@ static_lifetime_init(const irep_idt &identifier, symbol_tablet &symbol_table)
5353
if(type.id() == ID_code || type.id() == ID_empty)
5454
return {};
5555

56-
// We won't try to initialize any symbols that have
57-
// remained incomplete.
58-
59-
if(symbol.value.is_nil() && symbol.is_extern)
60-
// Compilers would usually complain about these
61-
// symbols being undefined.
62-
return {};
63-
6456
if(type.id() == ID_array && to_array_type(type).size().is_nil())
6557
{
6658
// C standard 6.9.2, paragraph 5
@@ -77,14 +69,18 @@ static_lifetime_init(const irep_idt &identifier, symbol_tablet &symbol_table)
7769
return {}; // do not initialize
7870
}
7971

80-
if(symbol.value.id() == ID_nondet)
81-
{
82-
return {}; // do not initialize
83-
}
84-
8572
exprt rhs;
8673

87-
if(symbol.value.is_nil())
74+
if((symbol.value.is_nil() && symbol.is_extern) ||
75+
symbol.value.id() == ID_nondet)
76+
{
77+
// Nondet initialise if not linked, or if explicitly requested.
78+
// Compilers would usually complain about the unlinked symbol case.
79+
const auto nondet = nondet_initializer(symbol.type, symbol.location, ns);
80+
CHECK_RETURN(nondet.has_value());
81+
rhs = *nondet;
82+
}
83+
else if(symbol.value.is_nil())
8884
{
8985
const auto zero = zero_initializer(symbol.type, symbol.location, ns);
9086
CHECK_RETURN(zero.has_value());

0 commit comments

Comments
 (0)