Add optional bounds to unroll loops in BMC model checker

This commit is contained in:
Pawel Gebal 2023-02-23 19:22:46 +01:00
parent dcecf00e30
commit f15b826431
131 changed files with 2200 additions and 146 deletions

View File

@ -32,6 +32,7 @@ Compiler Features:
* NatSpec: Include NatSpec from events that are emitted by a contract but defined outside of it in userdoc and devdoc output. * NatSpec: Include NatSpec from events that are emitted by a contract but defined outside of it in userdoc and devdoc output.
* Optimizer: Re-implement simplified version of ``UnusedAssignEliminator`` and ``UnusedStoreEliminator``. It can correctly remove some unused assignments in deeply nested loops that were ignored by the old version. * Optimizer: Re-implement simplified version of ``UnusedAssignEliminator`` and ``UnusedStoreEliminator``. It can correctly remove some unused assignments in deeply nested loops that were ignored by the old version.
* Parser: Unary plus is no longer recognized as a unary operator in the AST and triggers an error at the parsing stage (rather than later during the analysis). * Parser: Unary plus is no longer recognized as a unary operator in the AST and triggers an error at the parsing stage (rather than later during the analysis).
* SMTChecker: Add CLI option ``--model-checker-bmc-loop-iterations`` and a JSON option ``settings.modelChecker.bmcLoopIterations`` that specify how many loop iterations the BMC engine should unroll. Note that false negatives are possible when unrolling loops. This is due to the possibility that bmc loop iteration setting is less than actual number of iterations needed to complete a loop.
* SMTChecker: Group all messages about unsupported language features in a single warning. The CLI option ``--model-checker-show-unsupported`` and the JSON option ``settings.modelChecker.showUnsupported`` can be enabled to show the full list. * SMTChecker: Group all messages about unsupported language features in a single warning. The CLI option ``--model-checker-show-unsupported`` and the JSON option ``settings.modelChecker.showUnsupported`` can be enabled to show the full list.
* SMTChecker: Properties that are proved safe are now reported explicitly at the end of analysis. By default, only the number of safe properties is shown. The CLI option ``--model-checker-show-proved-safe`` and the JSON option ``settings.modelChecker.showProvedSafe`` can be enabled to show the full list of safe properties. * SMTChecker: Properties that are proved safe are now reported explicitly at the end of analysis. By default, only the number of safe properties is shown. The CLI option ``--model-checker-show-proved-safe`` and the JSON option ``settings.modelChecker.showProvedSafe`` can be enabled to show the full list of safe properties.
* Standard JSON Interface: Add experimental support for importing ASTs via Standard JSON. * Standard JSON Interface: Add experimental support for importing ASTs via Standard JSON.

View File

@ -18,7 +18,6 @@
#include <libsolidity/formal/BMC.h> #include <libsolidity/formal/BMC.h>
#include <libsolidity/formal/ModelChecker.h>
#include <libsolidity/formal/SymbolicTypes.h> #include <libsolidity/formal/SymbolicTypes.h>
#include <libsmtutil/SMTPortfolio.h> #include <libsmtutil/SMTPortfolio.h>
@ -26,6 +25,8 @@
#include <liblangutil/CharStream.h> #include <liblangutil/CharStream.h>
#include <liblangutil/CharStreamProvider.h> #include <liblangutil/CharStreamProvider.h>
#include <utility>
#ifdef HAVE_Z3_DLOPEN #ifdef HAVE_Z3_DLOPEN
#include <z3_version.h> #include <z3_version.h>
#endif #endif
@ -245,7 +246,7 @@ bool BMC::visit(IfStatement const& _node)
// We ignore called functions here because they have // We ignore called functions here because they have
// specific input values. // specific input values.
if (isRootFunction()) if (isRootFunction() && !isInsideLoop())
addVerificationTarget( addVerificationTarget(
VerificationTargetType::ConstantCondition, VerificationTargetType::ConstantCondition,
expr(_node.condition()), expr(_node.condition()),
@ -280,7 +281,7 @@ bool BMC::visit(Conditional const& _op)
m_context.pushSolver(); m_context.pushSolver();
_op.condition().accept(*this); _op.condition().accept(*this);
if (isRootFunction()) if (isRootFunction() && !isInsideLoop())
addVerificationTarget( addVerificationTarget(
VerificationTargetType::ConstantCondition, VerificationTargetType::ConstantCondition,
expr(_op.condition()), expr(_op.condition()),
@ -294,109 +295,172 @@ bool BMC::visit(Conditional const& _op)
return false; return false;
} }
// Here we consider the execution of two branches: // Unrolls while or do-while loop
// Branch 1 assumes the loop condition to be true and executes the loop once,
// after resetting touched variables.
// Branch 2 assumes the loop condition to be false and skips the loop after
// visiting the condition (it might contain side-effects, they need to be considered)
// and does not erase knowledge.
// If the loop is a do-while, condition side-effects are lost since the body,
// executed once before the condition, might reassign variables.
// Variables touched by the loop are merged with Branch 2.
bool BMC::visit(WhileStatement const& _node) bool BMC::visit(WhileStatement const& _node)
{ {
auto indicesBeforeLoop = copyVariableIndices(); unsigned int bmcLoopIterations = m_settings.bmcLoopIterations.value_or(1);
m_context.resetVariables(touchedVariables(_node)); smtutil::Expression broke(false);
decltype(indicesBeforeLoop) indicesAfterLoop; smtutil::Expression loopCondition(true);
if (_node.isDoWhile()) if (_node.isDoWhile())
{ {
indicesAfterLoop = visitBranch(&_node.body()).first; for (unsigned int i = 0; i < bmcLoopIterations; ++i)
// TODO the assertions generated in the body should still be active in the condition
_node.condition().accept(*this);
if (isRootFunction())
addVerificationTarget(
VerificationTargetType::ConstantCondition,
expr(_node.condition()),
&_node.condition()
);
}
else
{ {
m_loopCheckpoints.emplace();
auto indicesBefore = copyVariableIndices();
_node.body().accept(*this);
auto [continues, brokeInCurrentIteration] = mergeVariablesFromLoopCheckpoints();
auto indicesBreak = copyVariableIndices();
_node.condition().accept(*this); _node.condition().accept(*this);
if (isRootFunction()) mergeVariables(
addVerificationTarget( !brokeInCurrentIteration,
VerificationTargetType::ConstantCondition, copyVariableIndices(),
expr(_node.condition()), indicesBreak
&_node.condition()
); );
indicesAfterLoop = visitBranch(&_node.body(), expr(_node.condition())).first; mergeVariables(
broke || !loopCondition,
indicesBefore,
copyVariableIndices()
);
loopCondition = expr(_node.condition());
broke = broke || brokeInCurrentIteration;
m_loopCheckpoints.pop();
} }
}
// We reset the execution to before the loop else {
// and visit the condition in case it's not a do-while. smtutil::Expression loopConditionOnPreviousIteration(true);
// A do-while's body might have non-precise information for (unsigned int i = 0; i < bmcLoopIterations; ++i)
// in its first run about variables that are touched. {
resetVariableIndices(indicesBeforeLoop); m_loopCheckpoints.emplace();
if (!_node.isDoWhile()) auto indicesBefore = copyVariableIndices();
_node.condition().accept(*this); _node.condition().accept(*this);
loopCondition = expr(_node.condition());
mergeVariables(expr(_node.condition()), indicesAfterLoop, copyVariableIndices()); auto indicesAfterCondition = copyVariableIndices();
pushPathCondition(loopCondition);
_node.body().accept(*this);
popPathCondition();
auto [continues, brokeInCurrentIteration] = mergeVariablesFromLoopCheckpoints();
// merges indices modified when accepting loop condition that no longer holds
mergeVariables(
!loopCondition,
indicesAfterCondition,
copyVariableIndices()
);
// handles breaks in previous iterations
// breaks in current iterations are handled when traversing loop checkpoints
// handles case when the loop condition no longer holds but bmc loop iterations still unrolls the loop
mergeVariables(
broke || !loopConditionOnPreviousIteration,
indicesBefore,
copyVariableIndices()
);
m_loopCheckpoints.pop();
broke = broke || brokeInCurrentIteration;
loopConditionOnPreviousIteration = loopCondition;
}
}
if (bmcLoopIterations > 0)
m_context.addAssertion(not(loopCondition) || broke);
m_loopExecutionHappened = true; m_loopExecutionHappened = true;
return false; return false;
} }
// Here we consider the execution of two branches similar to WhileStatement. // Unrolls for loop
bool BMC::visit(ForStatement const& _node) bool BMC::visit(ForStatement const& _node)
{ {
if (_node.initializationExpression()) if (_node.initializationExpression())
_node.initializationExpression()->accept(*this); _node.initializationExpression()->accept(*this);
auto indicesBeforeLoop = copyVariableIndices(); smtutil::Expression broke(false);
smtutil::Expression forCondition(true);
// Do not reset the init expression part. smtutil::Expression forConditionOnPreviousIteration(true);
auto touchedVars = touchedVariables(_node.body()); unsigned int bmcLoopIterations = m_settings.bmcLoopIterations.value_or(1);
if (_node.condition()) for (unsigned int i = 0; i < bmcLoopIterations; ++i)
touchedVars += touchedVariables(*_node.condition()); {
if (_node.loopExpression()) auto indicesBefore = copyVariableIndices();
touchedVars += touchedVariables(*_node.loopExpression());
m_context.resetVariables(touchedVars);
if (_node.condition()) if (_node.condition())
{ {
_node.condition()->accept(*this); _node.condition()->accept(*this);
if (isRootFunction()) // values in loop condition might change during loop iteration
addVerificationTarget( forCondition = expr(*_node.condition());
VerificationTargetType::ConstantCondition, }
expr(*_node.condition()), m_loopCheckpoints.emplace();
_node.condition() auto indicesAfterCondition = copyVariableIndices();
pushPathCondition(forCondition);
_node.body().accept(*this);
auto [continues, brokeInCurrentIteration] = mergeVariablesFromLoopCheckpoints();
// accept loop expression if there was no break
if (_node.loopExpression())
{
auto indicesBreak = copyVariableIndices();
_node.loopExpression()->accept(*this);
mergeVariables(
!brokeInCurrentIteration,
copyVariableIndices(),
indicesBreak
); );
} }
popPathCondition();
m_context.pushSolver(); // merges indices modified when accepting loop condition that does no longer hold
if (_node.condition()) mergeVariables(
m_context.addAssertion(expr(*_node.condition())); !forCondition,
_node.body().accept(*this); indicesAfterCondition,
if (_node.loopExpression()) copyVariableIndices()
_node.loopExpression()->accept(*this); );
m_context.popSolver();
auto indicesAfterLoop = copyVariableIndices();
// We reset the execution to before the loop
// and visit the condition.
resetVariableIndices(indicesBeforeLoop);
if (_node.condition())
_node.condition()->accept(*this);
auto forCondition = _node.condition() ? expr(*_node.condition()) : smtutil::Expression(true);
mergeVariables(forCondition, indicesAfterLoop, copyVariableIndices());
// handles breaks in previous iterations
// breaks in current iterations are handled when traversing loop checkpoints
// handles case when the loop condition no longer holds but bmc loop iterations still unrolls the loop
mergeVariables(
broke || !forConditionOnPreviousIteration,
indicesBefore,
copyVariableIndices()
);
m_loopCheckpoints.pop();
broke = broke || brokeInCurrentIteration;
forConditionOnPreviousIteration = forCondition;
}
if (bmcLoopIterations > 0)
m_context.addAssertion(not(forCondition) || broke);
m_loopExecutionHappened = true; m_loopExecutionHappened = true;
return false; return false;
} }
std::tuple<smtutil::Expression, smtutil::Expression> BMC::mergeVariablesFromLoopCheckpoints()
{
smtutil::Expression continues(false);
smtutil::Expression brokeInCurrentIteration(false);
for (auto const& loopControl: m_loopCheckpoints.top())
{
// use SSAs associated with this break statement only if
// loop didn't break or continue earlier in the iteration
// loop condition is included in break path conditions
mergeVariables(
!brokeInCurrentIteration && !continues && loopControl.pathConditions,
loopControl.variableIndices,
copyVariableIndices()
);
if (loopControl.kind == LoopControlKind::Break)
brokeInCurrentIteration =
brokeInCurrentIteration || loopControl.pathConditions;
else if (loopControl.kind == LoopControlKind::Continue)
continues = continues || loopControl.pathConditions;
}
return std::pair(continues, brokeInCurrentIteration);
}
bool BMC::visit(TryStatement const& _tryStatement) bool BMC::visit(TryStatement const& _tryStatement)
{ {
FunctionCall const* externalCall = dynamic_cast<FunctionCall const*>(&_tryStatement.externalCall()); FunctionCall const* externalCall = dynamic_cast<FunctionCall const*>(&_tryStatement.externalCall());
@ -428,6 +492,28 @@ bool BMC::visit(TryStatement const& _tryStatement)
return false; return false;
} }
bool BMC::visit(Break const&)
{
LoopControl control = {
LoopControlKind::Break,
currentPathConditions(),
copyVariableIndices()
};
m_loopCheckpoints.top().emplace_back(control);
return false;
}
bool BMC::visit(Continue const&)
{
LoopControl control = {
LoopControlKind::Continue,
currentPathConditions(),
copyVariableIndices()
};
m_loopCheckpoints.top().emplace_back(control);
return false;
}
void BMC::endVisit(UnaryOperation const& _op) void BMC::endVisit(UnaryOperation const& _op)
{ {
SMTEncoder::endVisit(_op); SMTEncoder::endVisit(_op);
@ -535,7 +621,7 @@ void BMC::visitRequire(FunctionCall const& _funCall)
auto const& args = _funCall.arguments(); auto const& args = _funCall.arguments();
solAssert(args.size() >= 1, ""); solAssert(args.size() >= 1, "");
solAssert(args.front()->annotation().type->category() == Type::Category::Bool, ""); solAssert(args.front()->annotation().type->category() == Type::Category::Bool, "");
if (isRootFunction()) if (isRootFunction() && !isInsideLoop())
addVerificationTarget( addVerificationTarget(
VerificationTargetType::ConstantCondition, VerificationTargetType::ConstantCondition,
expr(*args.front()), expr(*args.front()),
@ -960,7 +1046,7 @@ void BMC::checkCondition(
vector<smtutil::Expression> expressionsToEvaluate; vector<smtutil::Expression> expressionsToEvaluate;
vector<string> expressionNames; vector<string> expressionNames;
tie(expressionsToEvaluate, expressionNames) = _modelExpressions; tie(expressionsToEvaluate, expressionNames) = _modelExpressions;
if (_callStack.size()) if (!_callStack.empty())
if (_additionalValue) if (_additionalValue)
{ {
expressionsToEvaluate.emplace_back(*_additionalValue); expressionsToEvaluate.emplace_back(*_additionalValue);
@ -973,8 +1059,9 @@ void BMC::checkCondition(
string extraComment = SMTEncoder::extraComment(); string extraComment = SMTEncoder::extraComment();
if (m_loopExecutionHappened) if (m_loopExecutionHappened)
extraComment += extraComment +=
"\nNote that some information is erased after the execution of loops.\n" "False negatives are possible when unrolling loops.\n"
"You can re-introduce information using require()."; "This is due to the possibility that the BMC loop iteration setting is"
" smaller than the actual number of iterations needed to complete a loop.";
if (m_externalFunctionCallHappened) if (m_externalFunctionCallHappened)
extraComment += extraComment +=
"\nNote that external function calls are not inlined," "\nNote that external function calls are not inlined,"
@ -1145,3 +1232,7 @@ void BMC::assignment(smt::SymbolicVariable& _symVar, smtutil::Expression const&
)); ));
} }
bool BMC::isInsideLoop() const
{
return !m_loopCheckpoints.empty();
}

View File

@ -100,6 +100,8 @@ private:
void endVisit(FunctionCall const& _node) override; void endVisit(FunctionCall const& _node) override;
void endVisit(Return const& _node) override; void endVisit(Return const& _node) override;
bool visit(TryStatement const& _node) override; bool visit(TryStatement const& _node) override;
bool visit(Break const& _node) override;
bool visit(Continue const& _node) override;
//@} //@}
/// Visitor helpers. /// Visitor helpers.
@ -188,6 +190,9 @@ private:
smtutil::CheckResult checkSatisfiable(); smtutil::CheckResult checkSatisfiable();
//@} //@}
std::tuple<smtutil::Expression, smtutil::Expression> mergeVariablesFromLoopCheckpoints();
bool isInsideLoop() const;
std::unique_ptr<smtutil::SolverInterface> m_interface; std::unique_ptr<smtutil::SolverInterface> m_interface;
/// Flags used for better warning messages. /// Flags used for better warning messages.
@ -204,6 +209,21 @@ private:
/// Number of verification conditions that could not be proved. /// Number of verification conditions that could not be proved.
size_t m_unprovedAmt = 0; size_t m_unprovedAmt = 0;
enum class LoopControlKind
{
Continue,
Break
}; };
// Current path conditions and SSA indices for break or continue statement
struct LoopControl {
LoopControlKind kind;
smtutil::Expression pathConditions;
VariableIndices variableIndices;
};
// Loop control statements for every loop
std::stack<std::vector<LoopControl>> m_loopCheckpoints;
};
} }

View File

@ -157,6 +157,7 @@ struct ModelCheckerExtCalls
struct ModelCheckerSettings struct ModelCheckerSettings
{ {
std::optional<unsigned> bmcLoopIterations;
ModelCheckerContracts contracts = ModelCheckerContracts::Default(); ModelCheckerContracts contracts = ModelCheckerContracts::Default();
/// Currently division and modulo are replaced by multiplication with slack vars, such that /// Currently division and modulo are replaced by multiplication with slack vars, such that
/// a / b <=> a = b * k + m /// a / b <=> a = b * k + m
@ -179,6 +180,7 @@ struct ModelCheckerSettings
bool operator==(ModelCheckerSettings const& _other) const noexcept bool operator==(ModelCheckerSettings const& _other) const noexcept
{ {
return return
bmcLoopIterations == _other.bmcLoopIterations &&
contracts == _other.contracts && contracts == _other.contracts &&
divModNoSlacks == _other.divModNoSlacks && divModNoSlacks == _other.divModNoSlacks &&
engine == _other.engine && engine == _other.engine &&

View File

@ -168,7 +168,9 @@ protected:
void endVisit(IndexAccess const& _node) override; void endVisit(IndexAccess const& _node) override;
void endVisit(IndexRangeAccess const& _node) override; void endVisit(IndexRangeAccess const& _node) override;
bool visit(InlineAssembly const& _node) override; bool visit(InlineAssembly const& _node) override;
bool visit(Break const&) override { return false; }
void endVisit(Break const&) override {} void endVisit(Break const&) override {}
bool visit(Continue const&) override { return false; }
void endVisit(Continue const&) override {} void endVisit(Continue const&) override {}
bool visit(TryCatchClause const&) override { return true; } bool visit(TryCatchClause const&) override { return true; }
void endVisit(TryCatchClause const&) override {} void endVisit(TryCatchClause const&) override {}

View File

@ -430,7 +430,7 @@ std::optional<Json::Value> checkSettingsKeys(Json::Value const& _input)
std::optional<Json::Value> checkModelCheckerSettingsKeys(Json::Value const& _input) std::optional<Json::Value> checkModelCheckerSettingsKeys(Json::Value const& _input)
{ {
static set<string> keys{"contracts", "divModNoSlacks", "engine", "extCalls", "invariants", "showProvedSafe", "showUnproved", "showUnsupported", "solvers", "targets", "timeout"}; static set<string> keys{"bmcLoopIterations", "contracts", "divModNoSlacks", "engine", "extCalls", "invariants", "showProvedSafe", "showUnproved", "showUnsupported", "solvers", "targets", "timeout"};
return checkKeys(_input, keys, "modelChecker"); return checkKeys(_input, keys, "modelChecker");
} }
@ -1013,6 +1013,16 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
ret.modelCheckerSettings.engine = *engine; ret.modelCheckerSettings.engine = *engine;
} }
if (modelCheckerSettings.isMember("bmcLoopIterations"))
{
if (!ret.modelCheckerSettings.engine.bmc)
return formatFatalError(Error::Type::JSONError, "settings.modelChecker.bmcLoopIterations requires the BMC engine to be enabled.");
if (modelCheckerSettings["bmcLoopIterations"].isUInt())
ret.modelCheckerSettings.bmcLoopIterations = modelCheckerSettings["bmcLoopIterations"].asUInt();
else
return formatFatalError(Error::Type::JSONError, "settings.modelChecker.bmcLoopIterations must be an unsigned integer.");
}
if (modelCheckerSettings.isMember("extCalls")) if (modelCheckerSettings.isMember("extCalls"))
{ {
if (!modelCheckerSettings["extCalls"].isString()) if (!modelCheckerSettings["extCalls"].isString())

View File

@ -76,6 +76,7 @@ static string const g_strModelCheckerShowUnsupported = "model-checker-show-unsup
static string const g_strModelCheckerSolvers = "model-checker-solvers"; static string const g_strModelCheckerSolvers = "model-checker-solvers";
static string const g_strModelCheckerTargets = "model-checker-targets"; static string const g_strModelCheckerTargets = "model-checker-targets";
static string const g_strModelCheckerTimeout = "model-checker-timeout"; static string const g_strModelCheckerTimeout = "model-checker-timeout";
static string const g_strModelCheckerBMCLoopIterations = "model-checker-bmc-loop-iterations";
static string const g_strNone = "none"; static string const g_strNone = "none";
static string const g_strNoOptimizeYul = "no-optimize-yul"; static string const g_strNoOptimizeYul = "no-optimize-yul";
static string const g_strOptimize = "optimize"; static string const g_strOptimize = "optimize";
@ -872,6 +873,12 @@ General Information)").c_str(),
"The default is a deterministic resource limit." "The default is a deterministic resource limit."
"A timeout of 0 means no resource/time restrictions for any query." "A timeout of 0 means no resource/time restrictions for any query."
) )
(
g_strModelCheckerBMCLoopIterations.c_str(),
po::value<unsigned>(),
"Set loop unrolling depth for BMC engine."
"Default is 1."
)
; ;
desc.add(smtCheckerOptions); desc.add(smtCheckerOptions);
@ -965,6 +972,7 @@ void CommandLineParser::processArgs()
{g_strModelCheckerInvariants, {InputMode::Compiler, InputMode::CompilerWithASTImport}}, {g_strModelCheckerInvariants, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
{g_strModelCheckerSolvers, {InputMode::Compiler, InputMode::CompilerWithASTImport}}, {g_strModelCheckerSolvers, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
{g_strModelCheckerTimeout, {InputMode::Compiler, InputMode::CompilerWithASTImport}}, {g_strModelCheckerTimeout, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
{g_strModelCheckerBMCLoopIterations, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
{g_strModelCheckerContracts, {InputMode::Compiler, InputMode::CompilerWithASTImport}}, {g_strModelCheckerContracts, {InputMode::Compiler, InputMode::CompilerWithASTImport}},
{g_strModelCheckerTargets, {InputMode::Compiler, InputMode::CompilerWithASTImport}} {g_strModelCheckerTargets, {InputMode::Compiler, InputMode::CompilerWithASTImport}}
}; };
@ -1337,6 +1345,13 @@ void CommandLineParser::processArgs()
if (m_args.count(g_strModelCheckerTimeout)) if (m_args.count(g_strModelCheckerTimeout))
m_options.modelChecker.settings.timeout = m_args[g_strModelCheckerTimeout].as<unsigned>(); m_options.modelChecker.settings.timeout = m_args[g_strModelCheckerTimeout].as<unsigned>();
if (m_args.count(g_strModelCheckerBMCLoopIterations))
{
if (!m_options.modelChecker.settings.engine.bmc)
solThrow(CommandLineValidationError, "BMC loop unrolling requires the BMC engine to be enabled");
m_options.modelChecker.settings.bmcLoopIterations = m_args[g_strModelCheckerBMCLoopIterations].as<unsigned>();
}
m_options.metadata.literalSources = (m_args.count(g_strMetadataLiteral) > 0); m_options.metadata.literalSources = (m_args.count(g_strMetadataLiteral) > 0);
m_options.modelChecker.initialize = m_options.modelChecker.initialize =
m_args.count(g_strModelCheckerContracts) || m_args.count(g_strModelCheckerContracts) ||

View File

@ -0,0 +1 @@
--model-checker-engine bmc --model-checker-bmc-loop-iterations 3

View File

@ -0,0 +1,11 @@
Warning: BMC: Assertion violation happens here.
--> model_checker_bmc_loop_iterations/input.sol:10:3:
|
10 | assert(x == 3);
| ^^^^^^^^^^^^^^
Note: Counterexample:
x = 2
Note: Callstack:
Note: False negatives are possible when unrolling loops.
This is due to the possibility that the BMC loop iteration setting is smaller than the actual number of iterations needed to complete a loop.

View File

@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0;
contract C
{
function f(uint x) public pure {
require(x == 0);
do {
++x;
} while (x < 2);
assert(x == 3);
}
}

View File

@ -0,0 +1 @@
--model-checker-engine bmc --model-checker-bmc-loop-iterations bmc

View File

@ -0,0 +1 @@
the argument ('bmc') for option '--model-checker-bmc-loop-iterations' is invalid

View File

@ -0,0 +1 @@
--model-checker-engine bmc --model-checker-bmc-loop-iterations

View File

@ -0,0 +1 @@
the argument ('model_checker_bmc_loop_iterations_no_argument/input.sol') for option '--model-checker-bmc-loop-iterations' is invalid

View File

@ -0,0 +1,29 @@
{
"language": "Solidity",
"sources":
{
"Source":
{
"content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0;
contract C
{
function f(uint x) public pure {
require(x == 0);
do {
++x;
} while (x < 2);
assert(x == 2);
}
}"
}
},
"settings":
{
"modelChecker":
{
"engine": "bmc",
"bmcLoopIterations": 3
}
}
}

View File

@ -0,0 +1,22 @@
{
"errors":
[
{
"component": "general",
"errorCode": "6002",
"formattedMessage": "Info: BMC: 1 verification condition(s) proved safe! Enable the model checker option \"show proved safe\" to see all of them.
",
"message": "BMC: 1 verification condition(s) proved safe! Enable the model checker option \"show proved safe\" to see all of them.",
"severity": "info",
"type": "Info"
}
],
"sources":
{
"Source":
{
"id": 0
}
}
}

View File

@ -0,0 +1,29 @@
{
"language": "Solidity",
"sources":
{
"Source":
{
"content": "// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0;
contract C
{
function f(uint x) public pure {
require(x == 0);
do {
++x;
} while (x < 2);
assert(x == 2);
}
}"
}
},
"settings":
{
"modelChecker":
{
"engine": "bmc",
"bmcLoopIterations": "bmc"
}
}
}

View File

@ -0,0 +1,12 @@
{
"errors":
[
{
"component": "general",
"formattedMessage": "settings.modelChecker.bmcLoopIterations must be an unsigned integer.",
"message": "settings.modelChecker.bmcLoopIterations must be an unsigned integer.",
"severity": "error",
"type": "JSONError"
}
]
}

View File

@ -122,6 +122,9 @@ SMTCheckerTest::SMTCheckerTest(string const& _filename): SyntaxTest(_filename, E
m_shouldRun = false; m_shouldRun = false;
#endif #endif
} }
auto const& bmcLoopIterations = m_reader.sizetSetting("BMCLoopIterations", 1);
m_modelCheckerSettings.bmcLoopIterations = std::optional<unsigned>{bmcLoopIterations};
} }
TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)

View File

@ -55,6 +55,8 @@ protected:
Set in m_modelCheckerSettings. Set in m_modelCheckerSettings.
SMTSolvers: `all`, `cvc4`, `z3`, `none`, where the default is `all`. SMTSolvers: `all`, `cvc4`, `z3`, `none`, where the default is `all`.
Set in m_modelCheckerSettings. Set in m_modelCheckerSettings.
BMCLoopIterations: number of loop iterations for BMC engine, the default is 1.
Set in m_modelCheckerSettings.
*/ */
ModelCheckerSettings m_modelCheckerSettings; ModelCheckerSettings m_modelCheckerSettings;

View File

@ -1,8 +0,0 @@
contract C
{
function f(bool x) public pure { require(x); for (;x;) {} }
}
// ====
// SMTEngine: all
// ----
// Warning 6838: (65-66): BMC: Condition is always true.

View File

@ -1,8 +0,0 @@
contract C
{
function f(bool x) public pure { require(x); while (x) {} }
}
// ====
// SMTEngine: all
// ----
// Warning 6838: (66-67): BMC: Condition is always true.

View File

@ -0,0 +1,16 @@
contract C
{
function f(uint x) public pure {
require(x == 0);
do {
++x;
} while (x < 2);
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,20 @@
contract C
{
function f() public pure {
uint x;
do {
++x;
{
++x;
++x;
}
} while (x < 3);
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 4 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,18 @@
contract C
{
function f() public pure {
uint x;
do {
if (x >= 2)
++x;
++x;
} while (x < 3);
assert(x == 4);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 5
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,15 @@
contract C {
function f() public pure {
uint x;
do {
++x;
} while (true);
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 1
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,22 @@
contract C {
uint x;
function condition() private returns(bool) {
++x;
return x < 3;
}
function f() public {
require(x == 0);
do {
} while (condition());
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 5
// ----
// Warning 2661: (77-80): BMC: Overflow (resulting value larger than 2**256 - 1) happens here.
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C
{
function f(uint x) public pure {
require(x == 0);
do {
++x;
} while (x < 2);
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Warning 4661: (102-116): BMC: Assertion violation happens here.
// Info 6002: BMC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x;
do {
++x;
break;
} while (x < 3);
assert(x == 0);
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 2
// ----
// Warning 5740: (87-92): Unreachable code.
// Warning 4661: (97-111): BMC: Assertion violation happens here.
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C {
function f() public pure {
uint x;
do {
++x;
continue;
} while (x < 2);
assert(x == 0);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 2
// ----
// Warning 4661: (100-114): BMC: Assertion violation happens here.
// Info 6002: BMC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C {
function f() public pure {
uint x;
do {
++x;
break;
} while (x < 3);
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Warning 5740: (87-92): Unreachable code.
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C {
function f() public pure {
uint x = 0;
do {
if (x > 0)
break;
++x;
} while (x < 3);
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x = 0;
do {
if (x >= 0) {
++x;
break;
}
++x;
} while (x < 3);
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x = 0;
do {
if (x > 0) {
++x;
break;
}
++x;
} while (x < 3);
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x = 0;
do {
++x;
if (x > 1) {
++x;
break;
}
} while (x < 3);
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,23 @@
contract C {
function f() public pure {
uint x;
do {
++x;
if (x > 0) {
x = 2;
break;
}
if (x > 1) {
x = 3;
break;
}
} while (x < 3);
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,23 @@
contract C {
function f() public pure {
uint x;
do {
++x;
if (x > 1) {
x = 3;
break;
}
if (x > 0) {
x = 2;
break;
}
} while (x < 3);
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C {
function f() public pure {
uint x;
do {
break;
} while (++x < 2);
// loop condition is not executed after break
assert(x == 0);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Warning 5740: (79-86): Unreachable code.
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,21 @@
contract C {
function f() public pure {
uint x;
do {
if (x > 1) {
break;
}
if (x >= 0) {
x = 10;
continue;
}
} while (x < 3);
assert(x == 10);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,22 @@
contract C {
function f() public pure {
uint x;
do {
if (x > 1) {
x = 3;
break;
}
if (x >= 0) {
x = 2;
continue;
}
} while (x < 4);
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x = 0;
do {
++x;
if (x == 3) {
continue;
}
++x;
} while (x < 3);
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,25 @@
contract C {
function f() public pure {
uint x = 0;
uint y = 0;
do {
++x;
if (x == 2) {
++x;
y = 1;
continue;
}
if (x == 3) {
y = 2;
continue;
}
} while (x < 3);
assert(y == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,24 @@
contract C {
function f() public pure {
uint x = 0;
uint y = 0;
do {
++x;
if (x > 0) {
y = 1;
continue;
}
if (x > 0) {
y = 2;
continue;
}
} while (x < 3);
assert(y == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,25 @@
contract C
{
function f(uint x) public pure {
require(x == 0);
uint i;
do {
++i;
if (i == 2) {
x = 2;
continue;
}
if (i == 1) {
x = 1;
continue;
}
} while (i < 3);
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,22 @@
contract C
{
function f(uint z) public pure {
uint x = 0;
require(z == 0);
do {
uint y = 0;
do {
++z;
++y;
} while (y < 2);
++x;
} while (x < 2);
assert(z == 4);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 4 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,24 @@
contract C
{
function f(uint z) public pure {
uint x = 0;
require(z == 0);
do {
uint y = 0;
do {
if (y > 0)
break;
++z;
++y;
} while (y < 2);
++x;
} while (x < 2);
assert(z == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 4 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,24 @@
contract C
{
function f(uint z) public pure {
uint x = 0;
require(z == 0);
do {
uint y = 0;
do {
++y;
if (y > 0)
continue;
++z;
} while (y < 2);
++x;
} while (x < 2);
assert(z == 0);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 4 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,20 @@
contract C {
function f() public pure {
uint x = 0;
int y = 0;
do {
if (x >= 3)
y = 1;
++x;
} while (x < 3 || y == 1);
// BMC loop iteration setting is not enough to leave the loop
assert(x == 0); // should hold - no assumptions on value if didn't complete loop
assert(y == 0); // should hold - no assumptions on value if didn't complete loop
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 1
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,20 @@
contract C {
function f() public pure {
uint x = 0;
int y = 0;
do {
if (x >= 3)
y = 1;
++x;
} while (x < 3 || y == 1);
// BMC loop iteration setting is just enough to leave the loop
assert(x == 3); // should hold
assert(y == 1); // should hold
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,20 @@
contract C {
function f() public pure {
uint x = 0;
int y = 0;
do {
if (x >= 3)
y = 1;
++x;
} while (x < 3 || y == 1);
// BMC loop iteration setting is more than enough to leave the loop
assert(x == 3); // should hold
assert(y == 1); // should hold
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 5
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f(uint x) public pure {
require(x == 0);
uint y;
do {
++y;
if (y == 2)
x = 3;
} while (y < 3);
// nothing is reported because loop condition is true after unrolling the loop one time
assert(x == 4);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 1
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -1,19 +0,0 @@
contract C
{
function f(uint x) public pure {
require(x < 100);
for(uint i = 0; i < 10; ++i) {
// Overflows due to resetting x.
x = x + 1;
}
assert(x < 14);
}
}
// ====
// SMTEngine: all
// SMTSolvers: z3
// ----
// Warning 4984: (143-148): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here.
// Warning 6328: (156-170): CHC: Assertion violation happens here.
// Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.
// Warning 2661: (143-148): BMC: Overflow (resulting value larger than 2**256 - 1) happens here.

View File

@ -14,4 +14,4 @@ contract C
// ---- // ----
// Warning 4984: (106-111): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. // Warning 4984: (106-111): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here.
// Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. // Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.
// Warning 2661: (106-111): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. // Info 6002: BMC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,15 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 2; ++i)
++x;
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,15 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i)
x = i;
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,16 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i)
if (i > 1)
x = 10;
assert(x == 10);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,15 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 0; ++i)
++x;
assert(x == 0);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,14 @@
contract C
{
function f() public pure {
uint x;
for (; x < 0; ++x) {}
assert(x == 0);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 1
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,16 @@
contract C
{
function f() public pure {
uint x = 0;
for (uint i = 1; i < 3;) {
x = i;
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,23 @@
contract C
{
uint x;
function condition() private returns(bool) {
++x;
return x < 3;
}
function f() public {
require(x == 0);
for (; condition();) {
}
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 5
// ----
// Warning 2661: (71-74): BMC: Overflow (resulting value larger than 2**256 - 1) happens here.
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,31 @@
contract C
{
uint x;
uint y;
function condition() private returns(bool) {
++x;
return x < 3;
}
function expression() private {
++y;
}
function f() public {
require(x == 0);
require(y == 0);
for (; condition(); expression()) {
}
assert(x == 3);
assert(y == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 5
// ----
// Warning 2661: (80-83): BMC: Overflow (resulting value larger than 2**256 - 1) happens here.
// Warning 2661: (140-143): BMC: Overflow (resulting value larger than 2**256 - 1) happens here.
// Info 6002: BMC: 4 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,16 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 2; ++i)
++x;
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Warning 4661: (92-106): BMC: Assertion violation happens here.
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x;
for (uint i = 0; i < 2; ++i) {
++x;
break;
}
assert(x == 0);
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Warning 5740: (77-80): Unreachable code.
// Warning 4661: (108-122): BMC: Assertion violation happens here.
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C {
function f() public pure {
uint x;
for (uint i = 0; i < 2; ++i) {
++x;
continue;
}
assert(x == 0);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Warning 4661: (111-125): BMC: Assertion violation happens here.
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i) {
break;
++x;
}
assert(x == 0);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Warning 5740: (77-80): Unreachable code.
// Warning 5740: (97-100): Unreachable code.
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,18 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i) {
++x;
break;
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Warning 5740: (77-80): Unreachable code.
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,18 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i) {
if (i > 0)
break;
++x;
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,18 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i) {
++x;
if (i > 0)
break;
}
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,23 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i) {
if (i > 1) {
x = 1;
break;
}
if (i > 1) {
x = 2;
break;
}
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,23 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i) {
if (i > 1) {
x = 1;
break;
}
if (i >= 1) {
x = 2;
break;
}
}
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C
{
function f() public pure {
uint x;
for (;;) {
++x;
break;
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,18 @@
contract C
{
function f() public pure {
uint x;
for (;;) {
break;
++x;
}
assert(x == 0);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Warning 5740: (78-81): Unreachable code.
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C
{
function f() public pure {
uint x;
for (;x < 2;) {
++x;
break;
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,22 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i) {
if (i > 1) {
break;
}
if (i >= 0) {
x = 10;
continue;
}
}
assert(x == 10);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,23 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 2; ++i) {
if (i > 0) {
x = 1;
break;
}
if (i >= 0) {
x = 2;
continue;
}
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 2
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,22 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 3; ++i) {
if (i > 0) {
x = 1;
break;
} else {
x = 2;
continue;
}
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,18 @@
contract C
{
function f(uint x) public pure {
require(x == 0);
for (uint i = 0; i < 3; ++i) {
if (i > 1)
continue;
++x;
}
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,23 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 2; ++i) {
if (i == 1) {
x = 1;
continue;
}
if (i == 0) {
x = 2;
continue;
}
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,24 @@
contract C
{
function f(uint x) public pure {
require(x == 0);
for (uint i = 0; i < 3; ++i) {
if (x > 1) {
x = 10;
continue;
}
if (x > 0) {
x = 11;
continue;
}
++x;
}
assert(x == 10);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,24 @@
contract C
{
function f() public pure {
uint x;
for (; x < 2; ++x) {
if (x > 1) {
x = 10;
continue;
}
if (x > 0) {
x = 11;
continue;
}
}
// x > 0 branch triggers x = 11 and continue triggers ++x loop expression
assert(x == 12);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C
{
function f() public pure {
uint x;
for (; x < 2; ++x) {
continue;
}
// loop expression is executed after continue
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,16 @@
contract C
{
function f() public pure {
uint x = 0;
for (;;) {
x = 1;
}
assert(x == 1000);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C
{
function f() public pure {
uint x;
for (uint i = 0; i < 2; ++i) {
for (uint j = 0; j < 2; ++j)
++x;
}
assert(x == 4);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 4 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,22 @@
contract C
{
function f(uint x) public pure {
require(x == 0);
for (uint i = 0; i < 2; ++i) {
for (uint j = 0; j < 2; ++j) {
x = x + 1;
break;
}
break;
}
assert(x == 1);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Warning 5740: (92-95): Unreachable code.
// Warning 5740: (126-129): Unreachable code.
// Info 6002: BMC: 4 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,20 @@
contract C
{
function f() public pure {
uint x = 0;
for (uint i = 0; i < 2; ++i) {
for (uint j = 0; j < 2; ++j) {
if (i > 0)
continue;
++x;
}
}
assert(x == 2);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 4 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x = 0;
int y = 0;
for (; x < 3 || y == 1; ++x) {
if (x >= 3)
y = 1;
}
// BMC loop iteration setting is not enough to leave the loop
assert(x == 0); // should hold - no assumptions on value if didn't complete loop
assert(y == 0); // should hold - no assumptions on value if didn't complete loop
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x = 0;
int y = 0;
for (; x < 3 || y == 1; ++x) {
if (x >= 3)
y = 1;
}
// BMC loop iteration setting is just enough to leave the loop
assert(x == 3); // should hold - no assumptions on value if didn't complete loop
assert(y == 0); // should hold - no assumptions on value if didn't complete loop
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 4
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x = 0;
int y = 0;
for (; x < 3 || y == 1; ++x) {
if (x >= 3)
y = 1;
}
// BMC loop iteration setting is more than enough to leave the loop
assert(x == 3); // should hold - no assumptions on value if didn't complete loop
assert(y == 0); // should hold - no assumptions on value if didn't complete loop
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 5
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C
{
function f() public pure {
uint x = 0;
for (uint i = 0; i < 2; ++i) {
++x;
}
// nothing is reported because loop condition is still true after BMCLoopIterations
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 1
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -10,4 +10,3 @@ contract C {
// SMTSolvers: z3 // SMTSolvers: z3
// ---- // ----
// Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. // Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.
// Warning 6838: (90-96): BMC: Condition is always true.

View File

@ -13,4 +13,3 @@ contract C {
// SMTSolvers: z3 // SMTSolvers: z3
// ---- // ----
// Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them. // Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.
// Warning 6838: (106-112): BMC: Condition is always true.

View File

@ -1,13 +0,0 @@
contract C {
function f(uint x) public pure {
require(x == 2);
for (; x > 2;) {}
assert(x == 2);
}
}
// ====
// SMTEngine: all
// SMTSolvers: z3
// ----
// Info 1391: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.
// Warning 6838: (90-95): BMC: Condition is always false.

View File

@ -0,0 +1,18 @@
contract C {
function f(uint x) public pure {
require(x == 0);
uint y;
while (y < 3) {
++y;
if (y == 2)
x = 3;
}
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 2
// ----
// Info 6002: BMC: 2 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,19 @@
contract C {
function f() public pure {
uint x;
while (x < 3) {
++x;
{
++x;
++x;
}
}
assert(x == 3);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 3
// ----
// Info 6002: BMC: 4 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

View File

@ -0,0 +1,17 @@
contract C {
function f() public pure {
uint x;
while (x < 3) {
if (x >= 2)
++x;
++x;
}
assert(x == 4);
}
}
// ====
// SMTEngine: bmc
// SMTSolvers: z3
// BMCLoopIterations: 5
// ----
// Info 6002: BMC: 3 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

Some files were not shown because too many files have changed in this diff Show More