-
Notifications
You must be signed in to change notification settings - Fork 273
Invariant macros with diagnostic information #2744
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
danpoe
merged 3 commits into
diffblue:develop
from
danpoe:feature/invariants-with-diagnostic-information
Aug 17, 2018
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
CORE | ||
dummy_parameter.c | ||
invariant-diagnostics | ||
^EXIT=(0|127|134|137)$ | ||
^SIGNAL=0$ | ||
--- begin invariant violation report --- | ||
invariant with diagnostics failure | ||
invariant diagnostics information | ||
^(Backtrace)|(Backtraces not supported)$ | ||
-- | ||
^warning: ignoring | ||
^VERIFICATION SUCCESSFUL$ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CORE | ||
dummy_parameter.c | ||
precondition-diagnostics | ||
^EXIT=(0|127|134|137)$ | ||
^SIGNAL=0$ | ||
--- begin invariant violation report --- | ||
precondition diagnostics information | ||
^(Backtrace)|(Backtraces not supported)$ | ||
-- | ||
^warning: ignoring | ||
^VERIFICATION SUCCESSFUL$ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CORE | ||
dummy_parameter.c | ||
postcondition-diagnostics | ||
^EXIT=(0|127|134|137)$ | ||
^SIGNAL=0$ | ||
--- begin invariant violation report --- | ||
postcondition diagnostics information | ||
^(Backtrace)|(Backtraces not supported)$ | ||
-- | ||
^warning: ignoring | ||
^VERIFICATION SUCCESSFUL$ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CORE | ||
dummy_parameter.c | ||
check-return-diagnostics | ||
^EXIT=(0|127|134|137)$ | ||
^SIGNAL=0$ | ||
--- begin invariant violation report --- | ||
check return diagnostics information | ||
^(Backtrace)|(Backtraces not supported)$ | ||
-- | ||
^warning: ignoring | ||
^VERIFICATION SUCCESSFUL$ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CORE | ||
dummy_parameter.c | ||
data-invariant-diagnostics | ||
^EXIT=(0|127|134|137)$ | ||
^SIGNAL=0$ | ||
--- begin invariant violation report --- | ||
data invariant diagnostics information | ||
^(Backtrace)|(Backtraces not supported)$ | ||
-- | ||
^warning: ignoring | ||
^VERIFICATION SUCCESSFUL$ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,10 +9,11 @@ Author: Martin Brain, [email protected] | |
#ifndef CPROVER_UTIL_INVARIANT_H | ||
#define CPROVER_UTIL_INVARIANT_H | ||
|
||
#include <cstdlib> | ||
#include <stdexcept> | ||
#include <type_traits> | ||
#include <string> | ||
#include <cstdlib> | ||
#include <tuple> | ||
#include <type_traits> | ||
|
||
/* | ||
** Invariants document conditions that the programmer believes to | ||
|
@@ -83,7 +84,7 @@ class invariant_failedt | |
const std::string reason; | ||
|
||
public: | ||
std::string what() const noexcept; | ||
virtual std::string what() const noexcept; | ||
|
||
invariant_failedt( | ||
const std::string &_file, | ||
|
@@ -102,9 +103,47 @@ class invariant_failedt | |
} | ||
}; | ||
|
||
/// A class that includes diagnostic information related to an invariant | ||
/// violation. | ||
class invariant_with_diagnostics_failedt : public invariant_failedt | ||
{ | ||
private: | ||
const std::string diagnostics; | ||
|
||
public: | ||
virtual std::string what() const noexcept; | ||
|
||
invariant_with_diagnostics_failedt( | ||
const std::string &_file, | ||
const std::string &_function, | ||
int _line, | ||
const std::string &_backtrace, | ||
const std::string &_condition, | ||
const std::string &_reason, | ||
const std::string &_diagnostics) | ||
: invariant_failedt( | ||
_file, | ||
_function, | ||
_line, | ||
_backtrace, | ||
_condition, | ||
_reason), | ||
diagnostics(_diagnostics) | ||
{ | ||
} | ||
}; | ||
|
||
// The macros MACRO<n> (e.g., INVARIANT2) are for internal use in this file | ||
// only. The corresponding macros that take a variable number of arguments (see | ||
// further below) should be used instead, which in turn call those with a fixed | ||
// number of arguments. For example, if INVARIANT(...) is called with two | ||
// arguments, it calls INVARIANT2(). | ||
|
||
#if defined(CPROVER_INVARIANT_CPROVER_ASSERT) | ||
// Used to allow CPROVER to check itself | ||
#define INVARIANT(CONDITION, REASON) \ | ||
#define INVARIANT2(CONDITION, REASON) \ | ||
__CPROVER_assert((CONDITION), "Invariant : " REASON) | ||
#define INVARIANT3(CONDITION, REASON, DIAGNOSTICS) \ | ||
__CPROVER_assert((CONDITION), "Invariant : " REASON) | ||
|
||
#define INVARIANT_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
|
@@ -115,14 +154,23 @@ class invariant_failedt | |
// This is *not* recommended as it can result in unpredictable behaviour | ||
// including silently reporting incorrect results. | ||
// This is also useful for checking side-effect freedom. | ||
#define INVARIANT(CONDITION, REASON) do {} while(false) | ||
#define INVARIANT2(CONDITION, REASON) \ | ||
do \ | ||
{ \ | ||
} while(false) | ||
#define INVARIANT3(CONDITION, REASON, DIAGNOSTICS) \ | ||
do \ | ||
{ \ | ||
} while(false) | ||
#define INVARIANT_STRUCTURED(CONDITION, TYPENAME, ...) do {} while(false) | ||
|
||
#elif defined(CPROVER_INVARIANT_ASSERT) | ||
// Not recommended but provided for backwards compatability | ||
#include <cassert> | ||
// NOLINTNEXTLINE(*) | ||
#define INVARIANT(CONDITION, REASON) assert((CONDITION) && ((REASON), true)) | ||
#define INVARIANT2(CONDITION, REASON) assert((CONDITION) && ((REASON), true)) | ||
#define INVARIANT3(CONDITION, REASON, DIAGNOSTICS) \ | ||
assert((CONDITION) && ((REASON), true)) /* NOLINT */ | ||
// NOLINTNEXTLINE(*) | ||
#define INVARIANT_STRUCTURED(CONDITION, TYPENAME, ...) assert((CONDITION)) | ||
#else | ||
|
@@ -185,8 +233,8 @@ invariant_violated_string( | |
const std::string &file, | ||
const std::string &function, | ||
const int line, | ||
const std::string &reason, | ||
const std::string &condition) | ||
const std::string &condition, | ||
const std::string &reason) | ||
{ | ||
invariant_violated_structured<invariant_failedt>( | ||
file, function, line, condition, reason); | ||
|
@@ -201,16 +249,54 @@ invariant_violated_string( | |
#define __this_function__ __func__ | ||
#endif | ||
|
||
#define INVARIANT(CONDITION, REASON) \ | ||
// We wrap macros that take __VA_ARGS__ as an argument with EXPAND_MACRO(). This | ||
// is to account for the behaviour of msvc, which otherwise would not expand | ||
// __VA_ARGS__ to multiple arguments in the outermost macro invocation. | ||
#define EXPAND_MACRO(x) x | ||
|
||
#define GET_MACRO(X1, X2, X3, X4, X5, X6, MACRO, ...) MACRO | ||
|
||
// This macro dispatches to the macros MACRO<n> (with 1 <= n <= 6) and calls | ||
// them with the arguments in __VA_ARGS__. The invocation of GET_MACRO() selects | ||
// MACRO<n> when __VA_ARGS__ consists of n arguments. | ||
#define REDIRECT(MACRO, ...) \ | ||
do \ | ||
{ \ | ||
EXPAND_MACRO( \ | ||
GET_MACRO( \ | ||
__VA_ARGS__, \ | ||
MACRO##6, \ | ||
MACRO##5, \ | ||
MACRO##4, \ | ||
MACRO##3, \ | ||
MACRO##2, \ | ||
MACRO##1, \ | ||
DUMMY_MACRO_ARG)(__VA_ARGS__)); \ | ||
} while(false) | ||
|
||
#define INVARIANT2(CONDITION, REASON) \ | ||
do /* NOLINT */ \ | ||
{ \ | ||
if(!(CONDITION)) \ | ||
invariant_violated_string( \ | ||
__FILE__, \ | ||
__this_function__, \ | ||
__LINE__, \ | ||
#CONDITION, \ | ||
(REASON)); /* NOLINT */ \ | ||
} while(false) | ||
|
||
#define INVARIANT3(CONDITION, REASON, DIAGNOSTICS) \ | ||
do /* NOLINT */ \ | ||
{ \ | ||
if(!(CONDITION)) \ | ||
invariant_violated_structured<invariant_with_diagnostics_failedt>( \ | ||
__FILE__, \ | ||
__this_function__, \ | ||
__LINE__, \ | ||
#CONDITION, \ | ||
(REASON), \ | ||
#CONDITION); /* NOLINT */ \ | ||
(DIAGNOSTICS)); /* NOLINT */ \ | ||
} while(false) | ||
|
||
#define INVARIANT_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
|
@@ -227,21 +313,27 @@ invariant_violated_string( | |
|
||
#endif // End CPROVER_DO_NOT_CHECK / CPROVER_ASSERT / ... if block | ||
|
||
// Short hand macros. The second variant of each one permits including an | ||
// explanation or structured exception, in which case they are synonyms | ||
// for INVARIANT. | ||
// Short hand macros. The variants *_STRUCTURED below allow to specify a custom | ||
// exception, and are equivalent to INVARIANT_STRUCTURED. | ||
|
||
// The condition should only contain (unmodified) arguments to the method. | ||
// Inputs include arguments passed to the function, as well as member | ||
// variables that the function may read. | ||
#define INVARIANT(...) EXPAND_MACRO(REDIRECT(INVARIANT, __VA_ARGS__)) | ||
|
||
// The condition should only contain (unmodified) inputs to the method. Inputs | ||
// include arguments passed to the function, as well as member variables that | ||
// the function may read. | ||
// "The design of the system means that the arguments to this method | ||
// will always meet this condition". | ||
// | ||
// The PRECONDITION documents / checks assumptions about the inputs | ||
// that is the caller's responsibility to make happen before the call. | ||
#define PRECONDITION(CONDITION) INVARIANT(CONDITION, "Precondition") | ||
#define PRECONDITION_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
INVARIANT_STRUCTURED(CONDITION, TYPENAME, __VA_ARGS__) | ||
#define PRECONDITION1(CONDITION) INVARIANT2(CONDITION, "Precondition") | ||
#define PRECONDITION2(CONDITION, DIAGNOSTICS) \ | ||
INVARIANT3(CONDITION, "Precondition", DIAGNOSTICS) | ||
|
||
#define PRECONDITION(...) EXPAND_MACRO(REDIRECT(PRECONDITION, __VA_ARGS__)) | ||
|
||
#define PRECONDITION_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
EXPAND_MACRO(INVARIANT_STRUCTURED(CONDITION, TYPENAME, __VA_ARGS__)) | ||
|
||
// The condition should only contain variables that will be returned / | ||
// output without further modification. | ||
|
@@ -251,9 +343,14 @@ invariant_violated_string( | |
// output when it returns, given that it was called with valid inputs. | ||
// Outputs include the return value of the function, as well as member | ||
// variables that the function may write. | ||
#define POSTCONDITION(CONDITION) INVARIANT(CONDITION, "Postcondition") | ||
#define POSTCONDITION_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
INVARIANT_STRUCTURED(CONDITION, TYPENAME, __VA_ARGS__) | ||
#define POSTCONDITION1(CONDITION) INVARIANT2(CONDITION, "Postcondition") | ||
#define POSTCONDITION2(CONDITION, DIAGNOSTICS) \ | ||
INVARIANT3(CONDITION, "Postcondition", DIAGNOSTICS) | ||
|
||
#define POSTCONDITION(...) EXPAND_MACRO(REDIRECT(POSTCONDITION, __VA_ARGS__)) | ||
|
||
#define POSTCONDITION_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
EXPAND_MACRO(INVARIANT_STRUCTURED(CONDITION, TYPENAME, __VA_ARGS__)) | ||
|
||
// The condition should only contain (unmodified) values that were | ||
// changed by a previous method call. | ||
|
@@ -263,28 +360,38 @@ invariant_violated_string( | |
// A difference between CHECK_RETURN and POSTCONDITION is that CHECK_RETURN is | ||
// a statement about what the caller expects from a function, whereas a | ||
// POSTCONDITION is a statement about guarantees made by the function itself. | ||
#define CHECK_RETURN(CONDITION) INVARIANT(CONDITION, "Check return value") | ||
#define CHECK_RETURN_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
INVARIANT_STRUCTURED(CONDITION, TYPENAME, __VA_ARGS__) | ||
#define CHECK_RETURN1(CONDITION) INVARIANT2(CONDITION, "Check return value") | ||
#define CHECK_RETURN2(CONDITION, DIAGNOSTICS) \ | ||
INVARIANT3(CONDITION, "Check return value", DIAGNOSTICS) | ||
|
||
#define CHECK_RETURN(...) EXPAND_MACRO(REDIRECT(CHECK_RETURN, __VA_ARGS__)) | ||
|
||
#define CHECK_RETURN_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
EXPAND_MACRO(INVARIANT_STRUCTURED(CONDITION, TYPENAME, __VA_ARGS__)) | ||
|
||
// This should be used to mark dead code | ||
#define UNREACHABLE INVARIANT(false, "Unreachable") | ||
#define UNREACHABLE_STRUCTURED(TYPENAME, ...) \ | ||
INVARIANT_STRUCTURED(false, TYPENAME, __VA_ARGS__) | ||
#define UNREACHABLE INVARIANT2(false, "Unreachable") | ||
#define UNREACHABLE_STRUCTURED(TYPENAME, ...) \ | ||
EXPAND_MACRO(INVARIANT_STRUCTURED(false, TYPENAME, __VA_ARGS__)) | ||
|
||
// This condition should be used to document that assumptions that are | ||
// made on goto_functions, goto_programs, exprts, etc. being well formed. | ||
// "The data structure is corrupt or malformed" | ||
#define DATA_INVARIANT(CONDITION, REASON) INVARIANT(CONDITION, REASON) | ||
#define DATA_INVARIANT_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
INVARIANT_STRUCTURED(CONDITION, TYPENAME, __VA_ARGS__) | ||
#define DATA_INVARIANT2(CONDITION, REASON) INVARIANT2(CONDITION, REASON) | ||
#define DATA_INVARIANT3(CONDITION, REASON, DIAGNOSTICS) \ | ||
INVARIANT3(CONDITION, REASON, DIAGNOSTICS) | ||
|
||
#define DATA_INVARIANT(...) EXPAND_MACRO(REDIRECT(DATA_INVARIANT, __VA_ARGS__)) | ||
|
||
#define DATA_INVARIANT_STRUCTURED(CONDITION, TYPENAME, ...) \ | ||
EXPAND_MACRO(INVARIANT_STRUCTURED(CONDITION, TYPENAME, __VA_ARGS__)) | ||
|
||
// Legacy annotations | ||
|
||
// The following should not be used in new code and are only intended | ||
// to migrate documentation and "error handling" in older code. | ||
#define TODO INVARIANT(false, "Todo") | ||
#define UNIMPLEMENTED INVARIANT(false, "Unimplemented") | ||
#define UNHANDLED_CASE INVARIANT(false, "Unhandled case") | ||
#define TODO INVARIANT2(false, "Todo") | ||
#define UNIMPLEMENTED INVARIANT2(false, "Unimplemented") | ||
#define UNHANDLED_CASE INVARIANT2(false, "Unhandled case") | ||
|
||
#endif // CPROVER_UTIL_INVARIANT_H |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 was this order changed?
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 is so the argument order of
invariant_violated_string
andinvariant_violated_structured
is consistent.