-
Notifications
You must be signed in to change notification settings - Fork 274
Fix symex of functions that may throw #4343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
46ba4e7
3d46af3
c12ff79
d341910
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
public class Test { | ||
|
||
public static Test f(boolean unknown) throws Exception { | ||
|
||
if(unknown) | ||
throw new Exception(); | ||
else | ||
return new Test(); | ||
|
||
} | ||
|
||
public static void main(boolean unknown) { | ||
|
||
Sub s = new Sub(); // Make sure Sub is loaded | ||
int x = 0; | ||
|
||
// The routine below is repeated twice because historically symex could | ||
// behave differently the first and second times a may-throw function was | ||
// called. | ||
|
||
try { | ||
Test t1 = f(unknown); | ||
t1.f(); | ||
x += t1.g(); | ||
} | ||
catch(Exception e) { } | ||
|
||
try { | ||
Test t2 = f(unknown); | ||
t2.f(); | ||
x += t2.g(); | ||
} | ||
catch(Exception e) { } | ||
|
||
assert x == 10; | ||
|
||
} | ||
|
||
public void f() { } | ||
public int g() { return 5; } | ||
|
||
} | ||
|
||
class Sub extends Test { | ||
|
||
public void f() { } | ||
public int g() { return 0; } | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
CORE | ||
Test.class | ||
--function Test.main --show-vcc | ||
java::Test\.main:\(Z\)V::14::t1!0@1#\d+ = address_of\(symex_dynamic::dynamic_object\d+\) | ||
java::Test\.main:\(Z\)V::9::x!0@1#\d+ = 5 \+ java::Test\.main:\(Z\)V::9::x!0@1#\d+ | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
-- | ||
return_value!0#0 | ||
java::Sub\.g:\(\) | ||
-- | ||
This checks that when a function may throw, we can nonetheless constant-propagate | ||
and populate the value-set for the normal-return path. In particular we don't | ||
expect to see any reference to a zero-generation return value (indicating | ||
reading the return-value when not defined), nor do we expect to see any code | ||
from the Sub class, which is not accessible and can only be reached when | ||
constant propagation has lost information to the point we're not sure which type | ||
virtual calls against Test may find. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,14 +53,6 @@ static_lifetime_init(const irep_idt &identifier, symbol_tablet &symbol_table) | |
if(type.id() == ID_code || type.id() == ID_empty) | ||
return {}; | ||
|
||
// We won't try to initialize any symbols that have | ||
// remained incomplete. | ||
|
||
if(symbol.value.is_nil() && symbol.is_extern) | ||
// Compilers would usually complain about these | ||
// symbols being undefined. | ||
return {}; | ||
|
||
if(type.id() == ID_array && to_array_type(type).size().is_nil()) | ||
{ | ||
// C standard 6.9.2, paragraph 5 | ||
|
@@ -77,14 +69,18 @@ static_lifetime_init(const irep_idt &identifier, symbol_tablet &symbol_table) | |
return {}; // do not initialize | ||
} | ||
|
||
if(symbol.value.id() == ID_nondet) | ||
{ | ||
return {}; // do not initialize | ||
} | ||
|
||
exprt rhs; | ||
|
||
if(symbol.value.is_nil()) | ||
if((symbol.value.is_nil() && symbol.is_extern) || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this also cover There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checked: no, they are initialised by dangling globals So it's not trivial to fix this, but I think we're safe: there's no way for |
||
symbol.value.id() == ID_nondet) | ||
{ | ||
// Nondet initialise if not linked, or if explicitly requested. | ||
// Compilers would usually complain about the unlinked symbol case. | ||
const auto nondet = nondet_initializer(symbol.type, symbol.location, ns); | ||
CHECK_RETURN(nondet.has_value()); | ||
rhs = *nondet; | ||
} | ||
else if(symbol.value.is_nil()) | ||
{ | ||
const auto zero = zero_initializer(symbol.type, symbol.location, ns); | ||
CHECK_RETURN(zero.has_value()); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(commit message) convergeance -> convergence