mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[SMTChecker] Fix ICE when reporting cex concerning state vars from different source files
This commit is contained in:
parent
67c855e93e
commit
4214cd1354
@ -28,6 +28,7 @@ Bugfixes:
|
|||||||
* SMTChecker: Fix internal error when using compound bitwise assignment operators inside branches.
|
* SMTChecker: Fix internal error when using compound bitwise assignment operators inside branches.
|
||||||
* SMTChecker: Fix internal error when inlining a function that returns a tuple containing an unsupported type inside a branch.
|
* SMTChecker: Fix internal error when inlining a function that returns a tuple containing an unsupported type inside a branch.
|
||||||
* SMTChecker: Fix internal error when inlining functions that use state variables and belong to a different source.
|
* SMTChecker: Fix internal error when inlining functions that use state variables and belong to a different source.
|
||||||
|
* SMTChecker: Fix internal error when reporting counterexamples concerning state variables from different source files.
|
||||||
* View/Pure Checker: Properly detect state variable access through base class.
|
* View/Pure Checker: Properly detect state variable access through base class.
|
||||||
* Yul analyzer: Check availability of data objects already in analysis phase.
|
* Yul analyzer: Check availability of data objects already in analysis phase.
|
||||||
* Yul Optimizer: Fix an issue where memory-accessing code was removed even though ``msize`` was used in the program.
|
* Yul Optimizer: Fix an issue where memory-accessing code was removed even though ``msize`` was used in the program.
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <libdevcore/Assertions.h>
|
||||||
#include <libdevcore/Common.h> // defines noexcept macro for MSVC
|
#include <libdevcore/Common.h> // defines noexcept macro for MSVC
|
||||||
|
#include <libdevcore/Exceptions.h>
|
||||||
#include <liblangutil/CharStream.h>
|
#include <liblangutil/CharStream.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -31,6 +33,7 @@
|
|||||||
|
|
||||||
namespace langutil
|
namespace langutil
|
||||||
{
|
{
|
||||||
|
struct SourceLocationError: virtual dev::Exception {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of an interval of source positions.
|
* Representation of an interval of source positions.
|
||||||
@ -49,6 +52,15 @@ struct SourceLocation
|
|||||||
|
|
||||||
bool isEmpty() const { return start == -1 && end == -1; }
|
bool isEmpty() const { return start == -1 && end == -1; }
|
||||||
|
|
||||||
|
std::string text() const
|
||||||
|
{
|
||||||
|
assertThrow(source, SourceLocationError, "Requested text from null source.");
|
||||||
|
assertThrow(!isEmpty(), SourceLocationError, "Requested text from empty source location.");
|
||||||
|
assertThrow(start <= end, SourceLocationError, "Invalid source location.");
|
||||||
|
assertThrow(end <= int(source->source().length()), SourceLocationError, "Invalid source location.");
|
||||||
|
return source->source().substr(start, end - start);
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns the smallest SourceLocation that contains both @param _a and @param _b.
|
/// @returns the smallest SourceLocation that contains both @param _a and @param _b.
|
||||||
/// Assumes that @param _a and @param _b refer to the same source (exception: if the source of either one
|
/// Assumes that @param _a and @param _b refer to the same source (exception: if the source of either one
|
||||||
/// is unset, the source of the other will be used for the result, even if that is unset as well).
|
/// is unset, the source of the other will be used for the result, even if that is unset as well).
|
||||||
|
@ -43,12 +43,10 @@ BMC::BMC(smt::EncodingContext& _context, ErrorReporter& _errorReporter, map<h256
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void BMC::analyze(SourceUnit const& _source, shared_ptr<Scanner> const& _scanner, set<Expression const*> _safeAssertions)
|
void BMC::analyze(SourceUnit const& _source, set<Expression const*> _safeAssertions)
|
||||||
{
|
{
|
||||||
solAssert(_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker), "");
|
solAssert(_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker), "");
|
||||||
|
|
||||||
m_scanner = _scanner;
|
|
||||||
|
|
||||||
m_safeAssertions += move(_safeAssertions);
|
m_safeAssertions += move(_safeAssertions);
|
||||||
m_context.setSolver(m_interface);
|
m_context.setSolver(m_interface);
|
||||||
m_context.clear();
|
m_context.clear();
|
||||||
@ -542,7 +540,7 @@ pair<vector<smt::Expression>, vector<string>> BMC::modelExpressions()
|
|||||||
if (uf->annotation().type->isValueType())
|
if (uf->annotation().type->isValueType())
|
||||||
{
|
{
|
||||||
expressionsToEvaluate.emplace_back(expr(*uf));
|
expressionsToEvaluate.emplace_back(expr(*uf));
|
||||||
expressionNames.push_back(m_scanner->sourceAt(uf->location()));
|
expressionNames.push_back(uf->location().text());
|
||||||
}
|
}
|
||||||
|
|
||||||
return {expressionsToEvaluate, expressionNames};
|
return {expressionsToEvaluate, expressionNames};
|
||||||
@ -717,14 +715,11 @@ void BMC::checkCondition(
|
|||||||
vector<string> expressionNames;
|
vector<string> expressionNames;
|
||||||
tie(expressionsToEvaluate, expressionNames) = _modelExpressions;
|
tie(expressionsToEvaluate, expressionNames) = _modelExpressions;
|
||||||
if (callStack.size())
|
if (callStack.size())
|
||||||
{
|
|
||||||
solAssert(m_scanner, "");
|
|
||||||
if (_additionalValue)
|
if (_additionalValue)
|
||||||
{
|
{
|
||||||
expressionsToEvaluate.emplace_back(*_additionalValue);
|
expressionsToEvaluate.emplace_back(*_additionalValue);
|
||||||
expressionNames.push_back(_additionalValueName);
|
expressionNames.push_back(_additionalValueName);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
smt::CheckResult result;
|
smt::CheckResult result;
|
||||||
vector<string> values;
|
vector<string> values;
|
||||||
tie(result, values) = checkSatisfiableAndGenerateModel(expressionsToEvaluate);
|
tie(result, values) = checkSatisfiableAndGenerateModel(expressionsToEvaluate);
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
|
|
||||||
#include <libsolidity/interface/ReadFile.h>
|
#include <libsolidity/interface/ReadFile.h>
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
#include <liblangutil/Scanner.h>
|
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -56,7 +55,7 @@ class BMC: public SMTEncoder
|
|||||||
public:
|
public:
|
||||||
BMC(smt::EncodingContext& _context, langutil::ErrorReporter& _errorReporter, std::map<h256, std::string> const& _smtlib2Responses);
|
BMC(smt::EncodingContext& _context, langutil::ErrorReporter& _errorReporter, std::map<h256, std::string> const& _smtlib2Responses);
|
||||||
|
|
||||||
void analyze(SourceUnit const& _sources, std::shared_ptr<langutil::Scanner> const& _scanner, std::set<Expression const*> _safeAssertions);
|
void analyze(SourceUnit const& _sources, std::set<Expression const*> _safeAssertions);
|
||||||
|
|
||||||
/// This is used if the SMT solver is not directly linked into this binary.
|
/// This is used if the SMT solver is not directly linked into this binary.
|
||||||
/// @returns a list of inputs to the SMT solver that were not part of the argument to
|
/// @returns a list of inputs to the SMT solver that were not part of the argument to
|
||||||
|
@ -39,12 +39,10 @@ CHC::CHC(smt::EncodingContext& _context, ErrorReporter& _errorReporter):
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHC::analyze(SourceUnit const& _source, shared_ptr<Scanner> const& _scanner)
|
void CHC::analyze(SourceUnit const& _source)
|
||||||
{
|
{
|
||||||
solAssert(_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker), "");
|
solAssert(_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker), "");
|
||||||
|
|
||||||
m_scanner = _scanner;
|
|
||||||
|
|
||||||
#ifdef HAVE_Z3
|
#ifdef HAVE_Z3
|
||||||
auto z3Interface = dynamic_pointer_cast<smt::Z3CHCInterface>(m_interface);
|
auto z3Interface = dynamic_pointer_cast<smt::Z3CHCInterface>(m_interface);
|
||||||
solAssert(z3Interface, "");
|
solAssert(z3Interface, "");
|
||||||
|
@ -46,7 +46,7 @@ class CHC: public SMTEncoder
|
|||||||
public:
|
public:
|
||||||
CHC(smt::EncodingContext& _context, langutil::ErrorReporter& _errorReporter);
|
CHC(smt::EncodingContext& _context, langutil::ErrorReporter& _errorReporter);
|
||||||
|
|
||||||
void analyze(SourceUnit const& _sources, std::shared_ptr<langutil::Scanner> const& _scanner);
|
void analyze(SourceUnit const& _sources);
|
||||||
|
|
||||||
std::set<Expression const*> const& safeAssertions() const { return m_safeAssertions; }
|
std::set<Expression const*> const& safeAssertions() const { return m_safeAssertions; }
|
||||||
|
|
||||||
|
@ -29,13 +29,13 @@ ModelChecker::ModelChecker(ErrorReporter& _errorReporter, map<h256, string> cons
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelChecker::analyze(SourceUnit const& _source, shared_ptr<Scanner> const& _scanner)
|
void ModelChecker::analyze(SourceUnit const& _source)
|
||||||
{
|
{
|
||||||
if (!_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
|
if (!_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_chc.analyze(_source, _scanner);
|
m_chc.analyze(_source);
|
||||||
m_bmc.analyze(_source, _scanner, m_chc.safeAssertions());
|
m_bmc.analyze(_source, m_chc.safeAssertions());
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<string> ModelChecker::unhandledQueries()
|
vector<string> ModelChecker::unhandledQueries()
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
#include <libsolidity/interface/ReadFile.h>
|
#include <libsolidity/interface/ReadFile.h>
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
#include <liblangutil/Scanner.h>
|
|
||||||
|
|
||||||
namespace langutil
|
namespace langutil
|
||||||
{
|
{
|
||||||
@ -46,7 +45,7 @@ class ModelChecker
|
|||||||
public:
|
public:
|
||||||
ModelChecker(langutil::ErrorReporter& _errorReporter, std::map<h256, std::string> const& _smtlib2Responses);
|
ModelChecker(langutil::ErrorReporter& _errorReporter, std::map<h256, std::string> const& _smtlib2Responses);
|
||||||
|
|
||||||
void analyze(SourceUnit const& _sources, std::shared_ptr<langutil::Scanner> const& _scanner);
|
void analyze(SourceUnit const& _sources);
|
||||||
|
|
||||||
/// This is used if the SMT solver is not directly linked into this binary.
|
/// This is used if the SMT solver is not directly linked into this binary.
|
||||||
/// @returns a list of inputs to the SMT solver that were not part of the argument to
|
/// @returns a list of inputs to the SMT solver that were not part of the argument to
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include <libsolidity/ast/ASTVisitor.h>
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
#include <libsolidity/interface/ReadFile.h>
|
#include <libsolidity/interface/ReadFile.h>
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
#include <liblangutil/Scanner.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -231,7 +230,6 @@ protected:
|
|||||||
/// warning before the others in case it's needed.
|
/// warning before the others in case it's needed.
|
||||||
langutil::ErrorReporter m_errorReporter;
|
langutil::ErrorReporter m_errorReporter;
|
||||||
langutil::ErrorList m_smtErrors;
|
langutil::ErrorList m_smtErrors;
|
||||||
std::shared_ptr<langutil::Scanner> m_scanner;
|
|
||||||
|
|
||||||
/// Stores the current function/modifier call/invocation path.
|
/// Stores the current function/modifier call/invocation path.
|
||||||
std::vector<CallStackEntry> m_callStack;
|
std::vector<CallStackEntry> m_callStack;
|
||||||
|
@ -373,7 +373,7 @@ bool CompilerStack::analyze()
|
|||||||
{
|
{
|
||||||
ModelChecker modelChecker(m_errorReporter, m_smtlib2Responses);
|
ModelChecker modelChecker(m_errorReporter, m_smtlib2Responses);
|
||||||
for (Source const* source: m_sourceOrder)
|
for (Source const* source: m_sourceOrder)
|
||||||
modelChecker.analyze(*source->ast, source->scanner);
|
modelChecker.analyze(*source->ast);
|
||||||
m_unhandledSMTLib2Queries += modelChecker.unhandledQueries();
|
m_unhandledSMTLib2Queries += modelChecker.unhandledQueries();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,8 +257,11 @@ BOOST_AUTO_TEST_CASE(import_base)
|
|||||||
pragma solidity >=0.0;
|
pragma solidity >=0.0;
|
||||||
contract Base {
|
contract Base {
|
||||||
uint x;
|
uint x;
|
||||||
function f() internal {
|
address a;
|
||||||
|
function f() internal returns (uint) {
|
||||||
|
a = address(this);
|
||||||
++x;
|
++x;
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)"},
|
)"},
|
||||||
@ -268,7 +271,7 @@ BOOST_AUTO_TEST_CASE(import_base)
|
|||||||
import "base";
|
import "base";
|
||||||
contract Der is Base {
|
contract Der is Base {
|
||||||
function g(uint y) public {
|
function g(uint y) public {
|
||||||
f();
|
x += f();
|
||||||
assert(y > x);
|
assert(y > x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,6 +331,7 @@ BOOST_AUTO_TEST_CASE(import_library)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user