Skip to content

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

Merged

Conversation

smowton
Copy link
Contributor

@smowton smowton commented Mar 7, 2019

Java functions that may throw do not always define #return_value (cf. the C front-end ensures it always defines it, even if the source code does not). Previously that situation was handled inconsistently: the first call on any such path would propagate the value-set on the normal-return path but refuse to constant-propagate, and the second call on a path to the same function would refuse to do either (using return_value@object and return_value#0 to represent the possibility that the return-value is undefined in each case).

This partially addresses that by (a) using the same merge logic (keep the defined version) for #return_value variables as for locals, (b) erasing from the value-set when a variable dies rather than writing a failed object (consistent with the case where the variable has never been written at all), and (c) explicitly initialising nondet variables in the C front-end to permit (a).

With this change we can propagate the value-set to the normal-return path every time, and constant propagate on the first call to a given function.

One problem remains: on the second call constant propagation still fails, because we're merging an undefined generation of the #return_value variable (the one created by the previous DEAD instruction) but that generation is not zero. That case can be addressed once #4199 lands by having DEAD set the generation to zero (which is never defined) rather than incrementing it.

This is now based on #4386 -- please only review the last 4 commits.

@smowton smowton force-pushed the smowton/feature/explicily-initialise-externs branch 4 times, most recently from c2be99c to f0d7ae5 Compare March 14, 2019 16:18
@smowton
Copy link
Contributor Author

smowton commented Mar 14, 2019

@tautschnig @peterschrammel this should now be ready for review, but is based on #4386 -- please only review final 4 commits.

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: f0d7ae5).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/104456360

exprt rhs;

if(symbol.value.is_nil())
if((symbol.value.is_nil() && symbol.is_extern) ||
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also cover argc and argv?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked: no, they are initialised by dangling globals argc' and argv' created in ansi_c_entry_point, after static_lifetime_init has been called. I tried initialising them explicitly: this worked fine except for test goto-instrument/harness1, which tries to dump a C harness to replicate a particular situation. That led to a line like argv' = nondet_0();, which is not legal C.

So it's not trivial to fix this, but I think we're safe: there's no way for argc' and similar to be assigned, so they should never be merged. I agree it would be better to explicitly init them, but given the rabbit hole we appear to be diving down here I'm inclined to leave it to a subsequent PR.

@tautschnig tautschnig changed the title Fix symex of functions that may throw Fix symex of functions that may throw [depends-on: #4386] Mar 14, 2019
Copy link
Member

@peterschrammel peterschrammel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@@ -22,26 +22,13 @@ void goto_symext::symex_dead(statet &state)
const code_deadt &code = instruction.get_dead();

ssa_exprt ssa = state.rename_ssa<L1>(ssa_exprt{code.symbol()}, ns);

// in case of pointers, put something into the value set
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(commit message) convergeance -> convergence

return_value!0#0
java::Sub\.g:\(\)
--
This checks that when a function may throw, we can nontheless constant-propagate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nonetheless

smowton added 4 commits March 19, 2019 14:57
This enables us to distinguish the case where the front-end intended a nondet
initialiser from an undefined variable, such as a "#return_value" global before
a call or on paths which throw an exception.
This saves memory while achieving very similar behaviour as a read from a value removed from
the value-set still yields a failed object. The difference is what happens on a merge:
a merge with an explicit failed object retains it, while a merge against an empty value-set
will discard the undefined possibility. This is fine for dead variables, where on a control-
flow convergance we may safely assume we came from the path where it is not dead, but for
declarations and undefined extern variables the front-end and goto-symex must collaborate to
ensure an explicit nondet value is present.
Now that the front-ends are required to explicitly assign a nondet value where that
is intended (e.g. an undefined extern global), rather than leaving an undefined value,
there is no need to special-case merging them.
…unction

This is possible now that #return_value variables are not subject to special rules
in phi_function, and the value-set is cleared when variables are marked dead, meaning
that there is no chance a second function call which only sometimes defines #return_value
might witness the previous call's results.
@smowton smowton force-pushed the smowton/feature/explicily-initialise-externs branch from f0d7ae5 to d341910 Compare March 19, 2019 14:58
@smowton smowton changed the title Fix symex of functions that may throw [depends-on: #4386] Fix symex of functions that may throw Mar 19, 2019
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: d341910).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/104994782

@smowton smowton merged commit 589116d into diffblue:develop Mar 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants