Skip to content

New goto checker interfaces [blocks: 3579] #3564

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

peterschrammel
Copy link
Member

This will replace safety_checkert and property_checkert, and become the basis for breaking up the bmct monolith.
Based on #3557. Review only last commit.

I'm not happy with the naming of goto_checkert, which doesn't intuitively describe what it is doing - hoping for better suggestions from the reviewers.

  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

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.

🚫
This PR failed Diffblue compatibility checks (cbmc commit: c54e65f).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/94498702
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.

@peterschrammel peterschrammel changed the title New goto checker interfaces New goto checker interfaces [blocks 3565] Dec 12, 2018
@peterschrammel peterschrammel force-pushed the goto-checker-interfaces branch from c54e65f to d21bdf2 Compare December 16, 2018 16:24
@peterschrammel peterschrammel changed the title New goto checker interfaces [blocks 3565] New goto checker interfaces [depends: 3557] Dec 16, 2018
@peterschrammel peterschrammel changed the title New goto checker interfaces [depends: 3557] New goto checker interfaces [depends: 3557, blocks: 3579] Dec 16, 2018
@peterschrammel peterschrammel force-pushed the goto-checker-interfaces branch from d21bdf2 to 1968915 Compare December 16, 2018 17:12
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.

🚫
This PR failed Diffblue compatibility checks (cbmc commit: 1968915).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/94899319
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.

Copy link
Contributor

@romainbrenguier romainbrenguier left a comment

Choose a reason for hiding this comment

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

Some naming suggestions, otherwise looks fine

/// subsequent call to operator().
/// `goto_checkert` derivatives shall be implemented in a way such
/// that repeated calls to operator() shall return the next FAILed
/// property until eventually not returning any FAILing properties.
Copy link
Contributor

Choose a reason for hiding this comment

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

This last sentence is not clear, since the operator does not return a property.
And this sounds like something we would want to be enforced by the interface.

/// a goto model. It typically uses, but doesn't have to use, a
/// `goto_checkert` to iteratively determine the verification result
/// of each property.
class goto_verifiert
Copy link
Contributor

Choose a reason for hiding this comment

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

I think checker and verifier can easily be confused and the difference in meaning is not clear. I also can't find a very good naming for this two classes. Maybe this class is the one that should be goto_checker and the other one could be named something like incremental_goto_checker? since it's only checking until the next counter-example is found.

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1 - I also believe, but am not really sure, that the incremental nature is the difference? If this is correct, then the naming proposed by @romainbrenguier seems good; if it isn't, then the documentation needs to be revisited.

Copy link
Member Author

Choose a reason for hiding this comment

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

Going with incremental_goto_checkert due to lack of more intuitive names.

propertiest initialize_properties(const abstract_goto_modelt &goto_model)
{
propertiest properties;
forall_goto_functions(it, goto_model.get_goto_functions())
Copy link
Contributor

Choose a reason for hiding this comment

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

⛏️ an ranged-for would be preferred here, to make explicit that it is used just to access the data and not for other iterator operations. 🐇


const source_locationt &source_location = i_it->source_location;

irep_idt property_id = source_location.get_property_id();
Copy link
Contributor

Choose a reason for hiding this comment

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

⛏️ intermediary variable source_location is superfluous


const source_locationt &source_location = i_it->source_location;

irep_idt property_id = source_location.get_property_id();
Copy link
Contributor

Choose a reason for hiding this comment

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

should be const

struct property_infot
{
/// A pointer to the corresponding goto instruction
goto_programt::const_targett location;
Copy link
Contributor

Choose a reason for hiding this comment

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

The naming is a bit confusing as I would expect location to be a source_locationt. Could it be renamed to something like instruction_pointer?

Copy link
Member Author

Choose a reason for hiding this comment

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

Going with pc which is used in other classes such as goto_tracet.

/// the state of the analysis that it performs (e.g. goto-symex, solver, etc).
/// It is not responsible for maintaining outcomes (e.g. property results,
/// counterexamples, etc). However, an implementation may restrict the
/// sets of properties it is asked to check (e.g. only sequences of subsets).
Copy link
Collaborator

Choose a reason for hiding this comment

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

"subsets" of what?

Copy link
Member Author

@peterschrammel peterschrammel Jan 12, 2019

Choose a reason for hiding this comment

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

Please check whether it's clearer now.

/// one by one to the caller.
/// An implementation of `goto_checkert` is responsible for maintaining
/// the state of the analysis that it performs (e.g. goto-symex, solver, etc).
/// It is not responsible for maintaining outcomes (e.g. property results,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does "It" refer to the implementation? I'd use "An implementation of goto_checkert is not responsible for maintaining outcomes ..."

/// a goto model. It typically uses, but doesn't have to use, a
/// `goto_checkert` to iteratively determine the verification result
/// of each property.
class goto_verifiert
Copy link
Collaborator

Choose a reason for hiding this comment

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

+1 - I also believe, but am not really sure, that the incremental nature is the difference? If this is correct, then the naming proposed by @romainbrenguier seems good; if it isn't, then the documentation needs to be revisited.

{
/// The goto checker may be able to determine the results for more
/// properties if operator() is called again.
HAVE_MORE,
Copy link
Contributor

Choose a reason for hiding this comment

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

PARTIAL_RESULT?

};

/// Check whether the given properties with status UNKNOWN or newly
/// discovered properties hold
Copy link
Contributor

Choose a reason for hiding this comment

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

Newly discovered by the checker or by the caller?

Copy link
Member Author

Choose a reason for hiding this comment

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

Both, unfortunately.

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest adding that to the comment then

/// After returning DONE, another call to operator() with the same
/// properties will return DONE and leave the properties' results unchanged.
/// If there is a property with status FAIL then its counterexample
/// can be retrieved by calling `build_error_trace` before any
Copy link
Contributor

Choose a reason for hiding this comment

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

This sounds like it binds an implementation into an odd stateful implementation, how about just passing a boolean to operator() to indicate whether you want traces built or not?

Copy link
Member Author

Choose a reason for hiding this comment

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

  1. That will not make it less stateful if you still have to call a function to retrieve the trace.
  2. A bool should_build_trace together with optional<goto_tracet> has the problem of what to return when not buildlng a trace and the status is HAVE_MORE... an empty trace?
  3. One could have two operators: one that returns optional<goto_tracet> and another one that returns a status. The caller can pick which one to use depending on whether they want traces or not.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was envisaging something like std::pair<statust, optionalt<tracet>>, but option 3 sounds pretty good to me

Copy link
Member Author

Choose a reason for hiding this comment

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

Hm... having to decide whether I want a trace or not before actually knowing which property failed is a limitation for certain algorithms (e.g. synthesising invariants while checking properties: I don't need a counterexample when I fail due to a non-inductive invariant candidate, but I'd like to have the counterexample when a property fails).
So, I think the two operations should be separate. I'm not worried about the statefulness because it is quite natural.

/// The result status of a property
enum class property_resultt
{
/// The property was not reached (also used for initialization)
Copy link
Contributor

Choose a reason for hiding this comment

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

Not reached yet, I guess -- what's the difference between this and UNKNOWN?

Copy link
Contributor

Choose a reason for hiding this comment

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

It would rather be for unreachable assertions (for instance in methods that are loaded but not called from the entry point)

Copy link
Contributor

Choose a reason for hiding this comment

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

That seems the same as NOT_REACHABLE. Perhaps they should be NOT_REACHABLE and NOT_SATISFIABLE (can get there, but can't concurrently satisfy the condition)?

Copy link
Member Author

@peterschrammel peterschrammel Dec 17, 2018

Choose a reason for hiding this comment

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

I'll add examples to clarify these notions.

Copy link
Member Author

@peterschrammel peterschrammel Dec 17, 2018

Choose a reason for hiding this comment

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

Assume we run a path-symex that does at most 5 unwindings and stops
before exploring the else branch (*).

int main(int argc, char **argv)
{
  if(argc < 0)
    assert(0); // NOT_REACHABLE
  assert(argc >= 0); // PASS
  if(argc < 5)
  {
    for(int i=0; i<10; i++)
    {
      assert(i == 2) // FAIL
      assert(i != 15); // UNKNOWN
    }
  }
  else // (*)
  {
    assert(0); // NOT_REACHED
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

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

How about NOT_REACHED -> NOT_CHECKED? NOT_REACHED and NOT_REACHABLE are so close to synonyms it will surely confuse.

@smowton
Copy link
Contributor

smowton commented Dec 17, 2018

Re: naming both the checker and the verifier sound like they might be checking internal consistency of a GOTO program, rather than checking whether its assertions can be violated. Like Romain though I don't have a better idea.

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.

It would be good to apply Romain's comments, especially about the ranged for.

/// Check whether the given properties with status UNKNOWN or newly
/// discovered properties hold
/// \param [out] properties: Updates those properties whose
/// results have been determined. Newly discovered properties are added.
Copy link
Contributor

Choose a reason for hiding this comment

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

⛏️ Argument descriptions should talk about the arguments themselves, not the function. Maybe rephrase to:
Properties updated to whether their results have been determined.

/// property until eventually not returning any FAILing properties.
virtual statust operator()(propertiest &properties) = 0;

/// This builds and returns the counterexample
Copy link
Contributor

Choose a reason for hiding this comment

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

⛏️ Redundant This

UNREACHABLE;
}

/// Returns the properties in the goto model
Copy link
Contributor

Choose a reason for hiding this comment

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

⛏️ Returns -> Return

Copy link
Contributor

Choose a reason for hiding this comment

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

⛏️ And perhaps document that this function also initialises the properties (it's clear from the name, but it's confusing that the documentation doesn't match the function name).

propertiest properties;
forall_goto_functions(it, goto_model.get_goto_functions())
{
if(!it->second.is_inlined() || it->first == goto_functionst::entry_point())
Copy link
Contributor

Choose a reason for hiding this comment

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

⛏️ Maybe document why we exclude all inlined functions except the entry point?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a good question. It seems legacy to me and we should be able to remove this filter.
The first condition used to be necessary in times where goto_partial_inline was used.
The second condition is unclear to me (is the entry point marked inlined?). @kroening, @tautschnig, any insights?

Copy link
Collaborator

Choose a reason for hiding this comment

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

If the entry point were marked as inlined that would just seem wrong (and useless) to me. I'd suggest to remove this second part of the condition.

@tautschnig
Copy link
Collaborator

@peterschrammel Please send a ping when this one is ready for (re-)review.

@peterschrammel peterschrammel changed the title New goto checker interfaces [depends: 3557, blocks: 3579] New goto checker interfaces [blocks: 3579] Jan 9, 2019
@peterschrammel peterschrammel force-pushed the goto-checker-interfaces branch from 1968915 to e209fce Compare January 12, 2019 18:41
@peterschrammel
Copy link
Member Author

Please send a ping when this one is ready for (re-)review.

ping


/// An implementation of `goto_verifiert` checks all properties in
/// a goto model. It typically uses, but doesn't have to use, a
/// `goto_checkert` to iteratively determine the verification result
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this be incremental_goto_checkert?

{
return properties;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Needs a virtual ~goto_verifiert() = default;

@@ -0,0 +1,21 @@
/*******************************************************************\

Module: Goto Checker Interface
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit-pick: add "Incremental"

FOUND_FAIL,
/// The goto checker has returned all results for the given set
/// of properties.
DONE
Copy link
Collaborator

Choose a reason for hiding this comment

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

So what's the initial status to use then?

Copy link
Member Author

Choose a reason for hiding this comment

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

Why would you need an initial status?

Copy link
Collaborator

Choose a reason for hiding this comment

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

There always has to be some "status" - otherwise it's a "result" I'd say?

Copy link
Member Author

Choose a reason for hiding this comment

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

Made naming of result vs status more consistent

virtual statust operator()(propertiest &properties) = 0;

/// Builds and returns the counterexample
virtual goto_tracet build_error_trace() const = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we have move operators so that we can reasonably pass a goto_tracet by value?

Copy link
Member Author

Choose a reason for hiding this comment

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

Should be implicit

for(const auto &function_pair : goto_functions.function_map)
{
if(!function_pair.second.is_inlined() ||
function_pair.first == goto_functionst::entry_point())
Copy link
Collaborator

Choose a reason for hiding this comment

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

See comment on the earlier version: the second condition should be removed.

property_infot &property =
properties[i_it->source_location.get_property_id()];
property.result = property_resultt::NOT_CHECKED;
property.pc = i_it;
Copy link
Collaborator

Choose a reason for hiding this comment

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

A property_infot should have a constructor so that we can do
properties.emplace(i_it->source_location.get_property_id(), {property_resultt::NOT_CHECKED, i_it}); here.

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: f1f62b2).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/97146777

@peterschrammel peterschrammel force-pushed the goto-checker-interfaces branch from f1f62b2 to badcae8 Compare January 13, 2019 10:36
incremental_goto_checkert: returns a trace or 'done'
goto_verifiert: uses incremental_goto_checkert
                to check a set of properties
property utilities
@peterschrammel peterschrammel force-pushed the goto-checker-interfaces branch from badcae8 to a1100e1 Compare January 13, 2019 10:37
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: a1100e1).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/97160722

@peterschrammel peterschrammel merged commit bbfd361 into diffblue:develop Jan 13, 2019
@peterschrammel peterschrammel deleted the goto-checker-interfaces branch January 13, 2019 13:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants