-
Notifications
You must be signed in to change notification settings - Fork 273
Consistency between goto programs and symbol table #3118
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
Consistency between goto programs and symbol table #3118
Conversation
I'm not sure I'm convinced this is a design that is easy to extend - it seems each additional check will required about the same amount of changes? See #918 for an attempt of mine that should make it fairly easy to add new checks? |
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.
Some changes to be done, otherwise looks good to me.
src/goto-programs/goto_model.h
Outdated
@@ -18,6 +18,8 @@ Author: Daniel Kroening, [email protected] | |||
#include "abstract_goto_model.h" | |||
#include "goto_functions.h" | |||
|
|||
#include <iostream> |
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.
#include <iostream>
in a header is a very bad idea. Please remove this and move the implementation of check_id_consistency_symbol_table
to a .cpp
file.
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.
Ok, removed iostream
and reworked to use messaget
instance.
src/goto-programs/goto_model.h
Outdated
} | ||
if(!message_collector.empty()) | ||
{ | ||
std::cerr << "Error messages collected while checking the goto " |
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.
Also, can you see if you have a reference to a message handler like error()
or info()
, instead of writing to std::cerr
? If it's possible please do that instead.
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.
This PR failed Diffblue compatibility checks (cbmc commit: 0f2ee10).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/87188872
Status will be re-evaluated on next push.
Please contact @peterschrammel, @thk123, or @allredj for support.
Common spurious failures:
- the cbmc commit has disappeared in the mean time (e.g. in a force-push)
- the author is not in the list of contributors (e.g. first-time contributors).
3dfac03
to
30cc479
Compare
The second commit rewrites the functionality following #918 style to simplify adding further checks. |
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.
LGTM just one comment
src/goto-programs/goto_program.cpp
Outdated
|
||
switch(type) | ||
{ | ||
case GOTO: |
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.
I think this whole construct can be simplified, unless there's a reason not to? just keep the case ASSERT
and case FUNCTION_CALL
that require special handling, and just remove the other ones and add one default
?
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.
There's method in this madness. When we add further checks we simply put them under the right case, without having to add more cases. (At least I think so: this part I've also copied from #918.)
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.
Another thing to keep in mind is the semantics of what you've written. The behaviour is the same for all of case GOTO
, case ASSUME
and case ASSERT
for example, where for each one of them guard.visit(symbol_finder);
will run because of fall through of the switch cases. Is that intended, or only case ASSERT
should demonstrate that? If yes that's okay. If no, then what I suggested is a better/cleaner idea, and semantically correct while reducing the possibility of having cases being unintendedly massed together.
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.
This PR failed Diffblue compatibility checks (cbmc commit: 30cc479).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/87218803
Status will be re-evaluated on next push.
Please contact @peterschrammel, @thk123, or @allredj for support.
Common spurious failures:
- the cbmc commit has disappeared in the mean time (e.g. in a force-push)
- the author is not in the list of contributors (e.g. first-time contributors).
This first commit is just PR diffblue#3118 to reuse the common structure of checking this kind of consistency.
src/cbmc/cbmc_parse_options.cpp
Outdated
INVARIANT( | ||
!goto_model.check_internal_invariants(*this), | ||
"goto program internal invariants failed"); | ||
|
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.
Not entirely sure what the best approach is, but this might be relevant going forward as we extend this.
I'm considering calling my goto_program checks from the try block of cbmc_parse_optionst::get_goto_program so that any exceptions of type 'incorrect_goto_program_exceptiont' are caught there.
If called directly from the doit() method exceptions are then caught in parse_options_baset::main()
which has only the base exception type or the invalid_user_input_exceptiont type.
(I think)
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.
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.
Ok.
This first commit is just PR diffblue#3118 to reuse the common structure of checking this kind of consistency.
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.
Comment was addressed.
src/goto-programs/goto_program.cpp
Outdated
bool found_violation = false; | ||
std::vector<std::string> id_collector; | ||
auto symbol_finder = [&](const exprt &e) { | ||
if(e.id() == ID_symbol) |
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.
I think we should also check the types with IDs ID_symbol_type
, ID_struct_tag
, ID_c_enum_tag
, and ID_union_tag
here (see std_types.h
). Those types also hold an identifier which indexes into the symbol table.
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.
Ok, I've added those checks and reworked the code to use DATA_CHECK
.
src/goto-programs/goto_program.cpp
Outdated
{ | ||
auto symbol_expr = to_symbol_expr(e); | ||
if(!table.has_symbol(symbol_expr.get_identifier())) | ||
id_collector.push_back(id2string(symbol_expr.get_identifier())); |
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.
We could probably also use the DATA_CHECK()
macros here as in #3128. I was thinking if we want a third method where we keep going and report all errors we could add a third validation mode, say validation_modet::KEEP_GOING
which does not throw an exception or yield a DATA_INVARIANT
violation but instead prints the error messages to the error()
stream. But that's future work I'd say.
0da7ada
to
c668985
Compare
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.
Passed Diffblue compatibility checks (cbmc commit: c668985).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/87512935
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.
Passed Diffblue compatibility checks (cbmc commit: 8cb487f).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/87618130
8cb487f
to
af862d2
Compare
src/goto-programs/goto_function.h
Outdated
@@ -117,7 +117,59 @@ class goto_functiont | |||
/// reported via DATA_INVARIANT violations or exceptions. | |||
void validate(const namespacet &ns, const validation_modet vm) const | |||
{ | |||
body.validate(ns, vm); | |||
auto type_symbol_finder = |
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.
These seem very useful utilities - can we move them to/reconcile them with util/find_symbols.{h,cpp}
?
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.
Moved.
src/util/expr.cpp
Outdated
@@ -327,6 +327,24 @@ void exprt::visit(const_expr_visitort &visitor) const | |||
} | |||
} | |||
|
|||
void exprt::visit(const std::function<void(const exprt &)> &f) const |
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.
Ok, but we should really have this in a separate commit, it would in fact warrant both documentation and a unit test.
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.
Done.
6c6e5ca
to
0f33641
Compare
I've added a few fixes to appease the CI, then squashed. The above comments should all be addressed. |
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.
✔️
Passed Diffblue compatibility checks (cbmc commit: 0f33641).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/91887744
8a09089
to
aaf342a
Compare
@tautschnig I've rebased to include #3480 changes. |
@xbauch I'll take a look, but it seems CI is failing. |
aaf342a
to
bbeb694
Compare
@tautschnig Yes, my older tests were not smart enough for the new validation checks. Should be fine now. |
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.
Various smaller comments, but the part I'm most concerned about are the two new find_*
functions that don't actually seem to be "finding" much, but just doing the checking. I think these are two distinct activities.
src/util/expr.cpp
Outdated
{ | ||
std::stack<const exprt *> stack; | ||
stack.push(this); | ||
while(!stack.empty()) |
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.
Why is this not using the depth_iteratort
? And I don't think it actually implements the visitor pattern in any way? Maybe we should at least not call this method visit
?
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.
I haven't noticed we have iterators (probably confused by the existing visit
methods that do not use them). In which case I can as well call std::for_each
directly.
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.
And thus we don't need the unit test at all.
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.
Yay for less code!
src/util/expr.h
Outdated
@@ -305,6 +305,12 @@ class exprt:public irept | |||
void visit(class expr_visitort &visitor); | |||
void visit(class const_expr_visitort &visitor) const; | |||
|
|||
/// Recursively traverse the expression tree (via operands) and call \p f on | |||
/// every subexpressions, including `this`. The input function has | |||
/// side-effects and does not modify the expression. |
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.
"has no side-effects" - or "may have side-effects"? At least I don't understand why we would have to prescribe that this function has side effects (though arguably it might not make sense to do this if it does not have any effect).
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.
Changed to "may have side effects"
src/util/find_symbols.h
Outdated
|
||
class exprt; | ||
class symbol_exprt; | ||
class typet; | ||
class symbolt; | ||
class source_locationt; |
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.
Nit pick: lexicographic ordering.
src/goto-programs/goto_function.h
Outdated
@@ -118,6 +119,13 @@ class goto_functiont | |||
void validate(const namespacet &ns, const validation_modet vm) const | |||
{ | |||
body.validate(ns, vm); | |||
source_locationt nil_location; | |||
nil_location.make_nil(); |
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.
Is this important?
forall_subtypes(it, type) | ||
{ | ||
find_typetag_in_namespace(*it, nil_location, ns, vm); | ||
} |
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.
Hmm, I don't get the impression that this is doing much of a "find." Couldn't you actually use one of the find_*
functions to find the identifiers, and then check all of those that you have found?
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.
@tautschnig Ok, but this last bit required a bit more code change so I pushed it as a new commit and will squash once approved.
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.
🚫
This PR failed Diffblue compatibility checks (cbmc commit: bbeb694).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/93516892
Status will be re-evaluated on next push.
Please contact @peterschrammel, @thk123, or @allredj for support.
Common spurious failures:
- the cbmc commit has disappeared in the mean time (e.g. in a force-push)
- the author is not in the list of contributors (e.g. first-time contributors).
The incompatibility may have been introduced by an earlier PR. In that case merging this
PR should be avoided unless it fixes the current incompatibility.
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.
Looks good to me, especially the increased code reuse and less code being added.
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.
✔️
Passed Diffblue compatibility checks (cbmc commit: 559e78f).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/93639702
Iterate over all symbols in a goto program and for each one check that it is present in the symbol table as well. Includes a unit test for the check.
A simple iteration over goto-functions to check that it's base type is the same as the one stored in the symbol table. Includes a unit test.
Look up the symbol id in symbol table and call base_type_eq on every symbol expression in guard and code whenever relevant. Includes a unit test. Also fixes unit tests that these new checks brake.
559e78f
to
60a833e
Compare
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.
✔️
Passed Diffblue compatibility checks (cbmc commit: 60a833e).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/93651044
Introduce a chain of methods that (at the lowest level) iterate over all symbols
in a goto program and for each one check that it is present in the symbol table
as well. On the lower levels, the methods collect inconsistency messages and
print them to error output. On the top level, e.g. cbmc-parser, they return a
Boolean value to be caught by an invariant check.