Merge pull request #9106 from ethereum/develop

Merge develop into breaking.
This commit is contained in:
chriseth 2020-06-03 13:51:28 +02:00 committed by GitHub
commit c8b9d24eba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 1028 additions and 564 deletions

View File

@ -316,6 +316,15 @@ jobs:
name: checking shell scripts
command: ./scripts/chk_shellscripts/chk_shellscripts.sh
chk_errorcodes:
docker:
- image: circleci/python:3.6
steps:
- checkout
- run:
name: Check for error codes
command: ./scripts/fix_error_ids.py --check-only
chk_pylint:
docker:
- image: buildpack-deps:eoan
@ -845,6 +854,7 @@ workflows:
- chk_buglist: *workflow_trigger_on_tags
- chk_proofs: *workflow_trigger_on_tags
- chk_pylint: *workflow_trigger_on_tags
- chk_errorcodes: *workflow_trigger_on_tags
- chk_antlr_grammar: *workflow_trigger_on_tags
- chk_docs_pragma_min_version: *workflow_trigger_on_tags

View File

@ -25,20 +25,30 @@ Language Features:
Compiler Features:
* Code Generator: Do not introduce new source references for small internal routines.
* Build system: Update the soljson.js build to emscripten 1.39.15 and boost 1.73.0 and include Z3 for integrated SMTChecker support without the callback mechanism.
* Commandline Interface: Adds new option ``--base-path PATH`` to use the given path as the root of the source tree instead of the root of the filesystem.
* SMTChecker: Support array ``length``.
* SMTChecker: Support array ``push`` and ``pop``.
* SMTChecker: General support to BitVectors and the bitwise ``and`` operator.
* Add support for natspec comments on state variables.
Bugfixes:
* Optimizer: Fixed a bug in BlockDeDuplicator.
* Type Checker: Disallow assignments to storage variables of type ``mapping``.
* Type Checker: Disallow inline arrays of non-nameable types.
* Type Checker: Fix internal compiler error when accessing members of array slices.
* Type Checker: Fix internal compiler error when trying to decode too large static arrays.
* Type Checker: Fix wrong compiler error when referencing an overridden function without calling it.
* Type Checker: Fix internal compiler error when forward referencing non-literal constants from inline assembly.
* NatSpec: DocString block is terminated when encountering an empty line.
* Scanner: Fix bug when two empty NatSpec comments lead to scanning past EOL.
* Code Generator: Trigger proper unimplemented errors on certain array copy operations.
* SMTChecker: Fix internal error when applying arithmetic operators to fixed point variables.
* SMTChecker: Fix internal error when short circuiting Boolean expressions with function calls in state variable initialization.
* SMTChecker: Fix internal error when assigning to index access inside branches.
* SMTChecker: Fix internal error on try/catch clauses with parameters.
### 0.6.8 (2020-05-14)

View File

@ -16,8 +16,8 @@ This section lists changes where the behaviour of your code might
change without the compiler telling you about it.
* The resulting type of an exponentiation is the type of the base. It used to be the smallest type
that can hold both the type of the base and the type of the exponent, as with symmentric
operations. Additionally, signed types are allowed for the base of the exponetation.
that can hold both the type of the base and the type of the exponent, as with symmetric
operations. Additionally, signed types are allowed for the base of the exponentiation.
Explicitness Requirements
@ -36,9 +36,9 @@ For most of the topics the compiler will provide suggestions.
like so: ``override(Base1, Base2)``.
* Member-access to ``length`` of arrays is now always read-only, even for storage arrays. It is no
longer possible to resize storage arrays assigning a new value to their length. Use ``push()``,
``push(value)`` or ``pop()`` instead, or assign a full array, which will of course overwrite existing content.
The reason behind this is to prevent storage collisions by gigantic
longer possible to resize storage arrays by assigning a new value to their length. Use ``push()``,
``push(value)`` or ``pop()`` instead, or assign a full array, which will of course overwrite the existing content.
The reason behind this is to prevent storage collisions of gigantic
storage arrays.
* The new keyword ``abstract`` can be used to mark contracts as abstract. It has to be used
@ -86,7 +86,7 @@ New Features
============
This section lists things that were not possible prior to Solidity 0.6.0
or at least were more difficult to achieve prior to Solidity 0.6.0.
or were more difficult to achieve.
* The :ref:`try/catch statement <try-catch>` allows you to react on failed external calls.
* ``struct`` and ``enum`` types can be declared at file level.
@ -103,7 +103,7 @@ Interface Changes
This section lists changes that are unrelated to the language itself, but that have an effect on the interfaces of
the compiler. These may change the way how you use the compiler on the command line, how you use its programmable
interface or how you analyze the output produced by it.
interface, or how you analyze the output produced by it.
New Error Reporter
~~~~~~~~~~~~~~~~~~

View File

@ -76,7 +76,7 @@ are initialized with their :ref:`default value <default-value>` and have that
value until they are (re-)assigned.
You can either explicitly assign to return variables and
then leave the function using ``return;``,
then leave the function as above,
or you can provide return values
(either a single or :ref:`multiple ones<multi-return>`) directly with the ``return``
statement::
@ -94,8 +94,8 @@ statement::
}
}
This form is equivalent to first assigning values to the
return variables and then using ``return;`` to leave the function.
If you use an early ``return`` to leave a function that has return variables,
you must provide return values together with the return statement.
.. note::
You cannot return some types from non-internal functions, notably

View File

@ -44,8 +44,15 @@ An empty remapping prefix is not allowed.
If there are multiple matches due to remappings, the one with the longest common prefix is selected.
When accessing the filesystem to search for imports, all paths are treated as if they were fully qualified paths.
This behaviour can be customized by adding the command line option ``--base-path`` with a path to be prepended
before each filesystem access for imports is performed. Furthermore, the part added via ``--base-path``
will not appear in the contract metadata.
For security reasons the compiler has restrictions what directories it can access. Paths (and their subdirectories) of source files specified on the commandline and paths defined by remappings are allowed for import statements, but everything else is rejected. Additional paths (and their subdirectories) can be allowed via the ``--allow-paths /sample/path,/another/sample/path`` switch.
Everything inside the path specified via ``--base-path`` is always allowed.
If your contracts use :ref:`libraries <libraries>`, you will notice that the bytecode contains substrings of the form ``__$53aea86b7d70b31448b230b20ae141a537$__``. These are placeholders for the actual library addresses.
The placeholder is a 34 character prefix of the hex encoding of the keccak256 hash of the fully qualified library name.
The bytecode file will also contain lines of the form ``// <placeholder> -> <fq library name>`` at the end to help
@ -58,6 +65,7 @@ Either add ``--libraries "file.sol:Math:0x12345678901234567890123456789012345678
If ``solc`` is called with the option ``--link``, all input files are interpreted to be unlinked binaries (hex-encoded) in the ``__$53aea86b7d70b31448b230b20ae141a537$__``-format given above and are linked in-place (if the input is read from stdin, it is written to stdout). All options except ``--libraries`` are ignored (including ``-o``) in this case.
If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output. This is the recommended interface for more complex and especially automated uses. The process will always terminate in a "success" state and report any errors via the JSON output.
The option ``--base-path`` is also processed in standard-json mode.
.. note::
The library placeholder used to be the fully qualified name of the library itself

View File

@ -97,6 +97,7 @@ public:
/// Changes the source location used for each appended item.
void setSourceLocation(langutil::SourceLocation const& _location) { m_currentSourceLocation = _location; }
langutil::SourceLocation const& currentSourceLocation() const { return m_currentSourceLocation; }
/// Assembles the assembly into bytecode. The assembly should not be modified after this call, since the assembled version is cached.
LinkerObject const& assemble() const;

View File

@ -28,8 +28,6 @@ using namespace std;
using namespace solidity;
using namespace solidity::langutil;
ErrorId solidity::langutil::operator"" _error(unsigned long long _error) { return ErrorId{ _error }; }
ErrorReporter& ErrorReporter::operator=(ErrorReporter const& _errorReporter)
{
if (&_errorReporter == this)
@ -62,12 +60,12 @@ void ErrorReporter::warning(
error(_error, Error::Type::Warning, _location, _secondaryLocation, _description);
}
void ErrorReporter::error(ErrorId, Error::Type _type, SourceLocation const& _location, string const& _description)
void ErrorReporter::error(ErrorId _errorId, Error::Type _type, SourceLocation const& _location, string const& _description)
{
if (checkForExcessiveErrors(_type))
return;
auto err = make_shared<Error>(_type);
auto err = make_shared<Error>(_errorId, _type);
*err <<
errinfo_sourceLocation(_location) <<
util::errinfo_comment(_description);
@ -75,12 +73,12 @@ void ErrorReporter::error(ErrorId, Error::Type _type, SourceLocation const& _loc
m_errorList.push_back(err);
}
void ErrorReporter::error(ErrorId, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description)
void ErrorReporter::error(ErrorId _errorId, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description)
{
if (checkForExcessiveErrors(_type))
return;
auto err = make_shared<Error>(_type);
auto err = make_shared<Error>(_errorId, _type);
*err <<
errinfo_sourceLocation(_location) <<
errinfo_secondarySourceLocation(_secondaryLocation) <<
@ -102,7 +100,7 @@ bool ErrorReporter::checkForExcessiveErrors(Error::Type _type)
if (m_warningCount == c_maxWarningsAllowed)
{
auto err = make_shared<Error>(Error::Type::Warning);
auto err = make_shared<Error>(4591_error, Error::Type::Warning);
*err << util::errinfo_comment("There are more than 256 warnings. Ignoring the rest.");
m_errorList.push_back(err);
}
@ -116,7 +114,7 @@ bool ErrorReporter::checkForExcessiveErrors(Error::Type _type)
if (m_errorCount > c_maxErrorsAllowed)
{
auto err = make_shared<Error>(Error::Type::Warning);
auto err = make_shared<Error>(4013_error, Error::Type::Warning);
*err << util::errinfo_comment("There are more than 256 errors. Aborting.");
m_errorList.push_back(err);
BOOST_THROW_EXCEPTION(FatalError());

View File

@ -23,6 +23,7 @@
#pragma once
#include <libsolutil/CommonData.h>
#include <libsolutil/Exceptions.h>
#include <liblangutil/Exceptions.h>
#include <liblangutil/SourceLocation.h>
@ -33,17 +34,6 @@
namespace solidity::langutil
{
/**
* Unique identifiers are used to tag and track individual error cases.
* They are passed as the first parameter of error reporting functions.
* Suffix _error helps to find them in the sources.
* The struct ErrorId prevents incidental calls like typeError(3141) instead of typeError(3141_error).
* To create a new ID, one can add 0000_error and then run "python ./scripts/correct_error_ids.py"
* from the root of the repo.
*/
struct ErrorId { unsigned long long error = 0; };
ErrorId operator"" _error(unsigned long long error);
class ErrorReporter
{
public:

View File

@ -26,7 +26,8 @@ using namespace std;
using namespace solidity;
using namespace solidity::langutil;
Error::Error(Type _type, SourceLocation const& _location, string const& _description):
Error::Error(ErrorId _errorId, Type _type, SourceLocation const& _location, string const& _description):
m_errorId(_errorId),
m_type(_type)
{
switch (m_type)
@ -57,8 +58,8 @@ Error::Error(Type _type, SourceLocation const& _location, string const& _descrip
*this << util::errinfo_comment(_description);
}
Error::Error(Error::Type _type, std::string const& _description, SourceLocation const& _location):
Error(_type)
Error::Error(ErrorId _errorId, Error::Type _type, std::string const& _description, SourceLocation const& _location):
Error(_errorId, _type)
{
if (_location.isValid())
*this << errinfo_sourceLocation(_location);

View File

@ -56,6 +56,17 @@ struct InvalidAstError: virtual util::Exception {};
#define astAssert(CONDITION, DESCRIPTION) \
assertThrow(CONDITION, ::solidity::langutil::InvalidAstError, DESCRIPTION)
/**
* Unique identifiers are used to tag and track individual error cases.
* They are passed as the first parameter of error reporting functions.
* Suffix _error helps to find them in the sources.
* The struct ErrorId prevents incidental calls like typeError(3141) instead of typeError(3141_error).
* To create a new ID, one can add 0000_error and then run "python ./scripts/fix_error_ids.py"
* from the root of the repo.
*/
struct ErrorId { unsigned long long error = 0; };
constexpr ErrorId operator"" _error(unsigned long long _error) { return ErrorId{ _error }; }
class Error: virtual public util::Exception
{
public:
@ -69,14 +80,16 @@ public:
Warning
};
explicit Error(
Error(
ErrorId _errorId,
Type _type,
SourceLocation const& _location = SourceLocation(),
std::string const& _description = std::string()
);
Error(Type _type, std::string const& _description, SourceLocation const& _location = SourceLocation());
Error(ErrorId _errorId, Type _type, std::string const& _description, SourceLocation const& _location = SourceLocation());
ErrorId errorId() const { return m_errorId; }
Type type() const { return m_type; }
std::string const& typeName() const { return m_typeName; }
@ -100,6 +113,7 @@ public:
return true;
}
private:
ErrorId m_errorId;
Type m_type;
std::string m_typeName;
};

View File

@ -64,7 +64,7 @@ protected:
};
/// Location of the current token
SourceLocation currentLocation() const;
virtual SourceLocation currentLocation() const;
///@{
///@name Helper functions

View File

@ -23,6 +23,7 @@
#include <liblangutil/Exceptions.h>
#include <libsolutil/UTF8.h>
#include <iomanip>
#include <string_view>
using namespace std;
using namespace solidity;
@ -30,6 +31,20 @@ using namespace solidity::langutil;
using namespace solidity::util;
using namespace solidity::util::formatting;
namespace
{
std::string replaceNonTabs(std::string_view _utf8Input, char _filler)
{
std::string output;
for (char const c: _utf8Input)
if ((c & 0xc0) != 0x80)
output.push_back(c == '\t' ? '\t' : _filler);
return output;
}
}
AnsiColorized SourceReferenceFormatterHuman::normalColored() const
{
return AnsiColorized(m_stream, m_colored, {WHITE});
@ -85,6 +100,8 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _
frameColored() << "-->";
m_stream << ' ' << _ref.sourceName << ':' << line << ':' << (_ref.position.column + 1) << ":\n";
string_view text = _ref.text;
if (!_ref.multiline)
{
int const locationLength = _ref.endColumn - _ref.startColumn;
@ -96,21 +113,15 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _
// line 2:
frameColored() << line << " |";
m_stream << ' ' << _ref.text.substr(0, _ref.startColumn);
highlightColored() << _ref.text.substr(_ref.startColumn, locationLength);
m_stream << _ref.text.substr(_ref.endColumn) << '\n';
m_stream << ' ' << text.substr(0, _ref.startColumn);
highlightColored() << text.substr(_ref.startColumn, locationLength);
m_stream << text.substr(_ref.endColumn) << '\n';
// line 3:
m_stream << leftpad << ' ';
frameColored() << '|';
m_stream << ' ';
for_each(
_ref.text.cbegin(),
_ref.text.cbegin() + numCodepoints(_ref.text.substr(0, _ref.startColumn)),
[this](char ch) { m_stream << (ch == '\t' ? '\t' : ' '); }
);
diagColored() << string(numCodepoints(_ref.text.substr(_ref.startColumn, locationLength)), '^');
m_stream << ' ' << replaceNonTabs(text.substr(0, _ref.startColumn), ' ');
diagColored() << replaceNonTabs(text.substr(_ref.startColumn, locationLength), '^');
m_stream << '\n';
}
else
@ -122,13 +133,13 @@ void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _
// line 2:
frameColored() << line << " |";
m_stream << ' ' << _ref.text.substr(0, _ref.startColumn);
highlightColored() << _ref.text.substr(_ref.startColumn) << '\n';
m_stream << ' ' << text.substr(0, _ref.startColumn);
highlightColored() << text.substr(_ref.startColumn) << '\n';
// line 3:
m_stream << leftpad << ' ';
frameColored() << '|';
m_stream << ' ' << string(_ref.startColumn, ' ');
m_stream << ' ' << replaceNonTabs(text.substr(0, _ref.startColumn), ' ');
diagColored() << "^ (Relevant source part starts here and spans across multiple lines).";
m_stream << '\n';
}

View File

@ -19,6 +19,8 @@
#include <libsolutil/CommonIO.h>
#include <cvc4/util/bitvector.h>
using namespace std;
using namespace solidity;
using namespace solidity::util;
@ -185,6 +187,49 @@ CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr)
return m_context.mkExpr(CVC4::kind::INTS_DIVISION_TOTAL, arguments[0], arguments[1]);
else if (n == "mod")
return m_context.mkExpr(CVC4::kind::INTS_MODULUS, arguments[0], arguments[1]);
else if (n == "bvand")
return m_context.mkExpr(CVC4::kind::BITVECTOR_AND, arguments[0], arguments[1]);
else if (n == "int2bv")
{
size_t size = std::stoi(_expr.arguments[1].name);
auto i2bvOp = m_context.mkConst(CVC4::IntToBitVector(size));
// CVC4 treats all BVs as unsigned, so we need to manually apply 2's complement if needed.
return m_context.mkExpr(
CVC4::kind::ITE,
m_context.mkExpr(CVC4::kind::GEQ, arguments[0], m_context.mkConst(CVC4::Rational(0))),
m_context.mkExpr(CVC4::kind::INT_TO_BITVECTOR, i2bvOp, arguments[0]),
m_context.mkExpr(
CVC4::kind::BITVECTOR_NEG,
m_context.mkExpr(CVC4::kind::INT_TO_BITVECTOR, i2bvOp, m_context.mkExpr(CVC4::kind::UMINUS, arguments[0]))
)
);
}
else if (n == "bv2int")
{
auto intSort = dynamic_pointer_cast<IntSort>(_expr.sort);
smtAssert(intSort, "");
auto nat = m_context.mkExpr(CVC4::kind::BITVECTOR_TO_NAT, arguments[0]);
if (!intSort->isSigned)
return nat;
auto type = arguments[0].getType();
smtAssert(type.isBitVector(), "");
auto size = CVC4::BitVectorType(type).getSize();
// CVC4 treats all BVs as unsigned, so we need to manually apply 2's complement if needed.
auto extractOp = m_context.mkConst(CVC4::BitVectorExtract(size - 1, size - 1));
return m_context.mkExpr(CVC4::kind::ITE,
m_context.mkExpr(
CVC4::kind::EQUAL,
m_context.mkExpr(CVC4::kind::BITVECTOR_EXTRACT, extractOp, arguments[0]),
m_context.mkConst(CVC4::BitVector(1, size_t(0)))
),
nat,
m_context.mkExpr(
CVC4::kind::UMINUS,
m_context.mkExpr(CVC4::kind::BITVECTOR_TO_NAT, m_context.mkExpr(CVC4::kind::BITVECTOR_NEG, arguments[0]))
)
);
}
else if (n == "select")
return m_context.mkExpr(CVC4::kind::SELECT, arguments[0], arguments[1]);
else if (n == "store")
@ -201,7 +246,7 @@ CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr)
smtAssert(tupleSort, "");
CVC4::DatatypeType tt = m_context.mkTupleType(cvc4Sort(tupleSort->components));
CVC4::Datatype const& dt = tt.getDatatype();
size_t index = std::stoi(_expr.arguments[1].name);
size_t index = std::stoul(_expr.arguments[1].name);
CVC4::Expr s = dt[0][index].getSelector();
return m_context.mkExpr(CVC4::kind::APPLY_SELECTOR, s, arguments[0]);
}

View File

@ -126,7 +126,7 @@ pair<CheckResult, vector<string>> SMTLib2Interface::check(vector<Expression> con
result = CheckResult::ERROR;
vector<string> values;
if (result == CheckResult::SATISFIABLE && result != CheckResult::ERROR)
if (result == CheckResult::SATISFIABLE && !_expressionsToEvaluate.empty())
values = parseValues(find(response.cbegin(), response.cend(), '\n'), response.cend());
return make_pair(result, values);
}
@ -137,7 +137,40 @@ string SMTLib2Interface::toSExpr(Expression const& _expr)
return _expr.name;
std::string sexpr = "(";
if (_expr.name == "const_array")
if (_expr.name == "int2bv")
{
size_t size = std::stoi(_expr.arguments[1].name);
auto arg = toSExpr(_expr.arguments.front());
auto int2bv = "(_ int2bv " + to_string(size) + ")";
// Some solvers treat all BVs as unsigned, so we need to manually apply 2's complement if needed.
sexpr += string("ite ") +
"(>= " + arg + " 0) " +
"(" + int2bv + " " + arg + ") " +
"(bvneg (" + int2bv + " (- " + arg + ")))";
}
else if (_expr.name == "bv2int")
{
auto intSort = dynamic_pointer_cast<IntSort>(_expr.sort);
smtAssert(intSort, "");
auto arg = toSExpr(_expr.arguments.front());
auto nat = "(bv2nat " + arg + ")";
if (!intSort->isSigned)
return nat;
auto bvSort = dynamic_pointer_cast<BitVectorSort>(_expr.arguments.front().sort);
smtAssert(bvSort, "");
auto size = to_string(bvSort->size);
auto pos = to_string(bvSort->size - 1);
// Some solvers treat all BVs as unsigned, so we need to manually apply 2's complement if needed.
sexpr += string("ite ") +
"(= ((_ extract " + pos + " " + pos + ")" + arg + ") #b0) " +
nat + " " +
"(- (bvneg " + arg + "))";
}
else if (_expr.name == "const_array")
{
smtAssert(_expr.arguments.size() == 2, "");
auto sortSort = std::dynamic_pointer_cast<SortSort>(_expr.arguments.at(0).sort);
@ -151,7 +184,7 @@ string SMTLib2Interface::toSExpr(Expression const& _expr)
{
smtAssert(_expr.arguments.size() == 2, "");
auto tupleSort = dynamic_pointer_cast<TupleSort>(_expr.arguments.at(0).sort);
unsigned index = std::stoi(_expr.arguments.at(1).name);
size_t index = std::stoul(_expr.arguments.at(1).name);
smtAssert(index < tupleSort->members.size(), "");
sexpr += "|" + tupleSort->members.at(index) + "| " + toSExpr(_expr.arguments.at(0));
}

View File

@ -94,6 +94,9 @@ public:
{"*", 2},
{"/", 2},
{"mod", 2},
{"bvand", 2},
{"int2bv", 2},
{"bv2int", 1},
{"select", 2},
{"store", 3},
{"const_array", 2},
@ -195,6 +198,32 @@ public:
);
}
static Expression int2bv(Expression _n, size_t _size)
{
smtAssert(_n.sort->kind == Kind::Int, "");
std::shared_ptr<IntSort> intSort = std::dynamic_pointer_cast<IntSort>(_n.sort);
smtAssert(intSort, "");
smtAssert(_size <= 256, "");
return Expression(
"int2bv",
std::vector<Expression>{std::move(_n), Expression(_size)},
std::make_shared<BitVectorSort>(_size)
);
}
static Expression bv2int(Expression _bv, bool _signed = false)
{
smtAssert(_bv.sort->kind == Kind::BitVector, "");
std::shared_ptr<BitVectorSort> bvSort = std::dynamic_pointer_cast<BitVectorSort>(_bv.sort);
smtAssert(bvSort, "");
smtAssert(bvSort->size <= 256, "");
return Expression(
"bv2int",
std::vector<Expression>{std::move(_bv)},
SortProvider::intSort(_signed)
);
}
friend Expression operator!(Expression _a)
{
return Expression("not", std::move(_a), Kind::Bool);
@ -251,6 +280,11 @@ public:
{
return Expression("mod", std::move(_a), std::move(_b), Kind::Int);
}
friend Expression operator&(Expression _a, Expression _b)
{
auto bvSort = _a.sort;
return Expression("bvand", {std::move(_a), std::move(_b)}, bvSort);
}
Expression operator()(std::vector<Expression> _arguments) const
{
smtAssert(

View File

@ -24,6 +24,14 @@ namespace solidity::smtutil
{
shared_ptr<Sort> const SortProvider::boolSort{make_shared<Sort>(Kind::Bool)};
shared_ptr<Sort> const SortProvider::intSort{make_shared<Sort>(Kind::Int)};
shared_ptr<IntSort> const SortProvider::uintSort{make_shared<IntSort>(false)};
shared_ptr<IntSort> const SortProvider::sintSort{make_shared<IntSort>(true)};
shared_ptr<IntSort> SortProvider::intSort(bool _signed)
{
if (_signed)
return sintSort;
return uintSort;
}
}

View File

@ -31,6 +31,7 @@ enum class Kind
{
Int,
Bool,
BitVector,
Function,
Array,
Sort,
@ -48,6 +49,36 @@ struct Sort
};
using SortPointer = std::shared_ptr<Sort>;
struct IntSort: public Sort
{
IntSort(bool _signed):
Sort(Kind::Int),
isSigned(_signed)
{}
bool operator==(IntSort const& _other) const
{
return Sort::operator==(_other) && isSigned == _other.isSigned;
}
bool isSigned;
};
struct BitVectorSort: public Sort
{
BitVectorSort(unsigned _size):
Sort(Kind::BitVector),
size(_size)
{}
bool operator==(BitVectorSort const& _other) const
{
return Sort::operator==(_other) && size == _other.size;
}
unsigned size;
};
struct FunctionSort: public Sort
{
FunctionSort(std::vector<SortPointer> _domain, SortPointer _codomain):
@ -160,7 +191,9 @@ struct TupleSort: public Sort
struct SortProvider
{
static std::shared_ptr<Sort> const boolSort;
static std::shared_ptr<Sort> const intSort;
static std::shared_ptr<IntSort> const uintSort;
static std::shared_ptr<IntSort> const sintSort;
static std::shared_ptr<IntSort> intSort(bool _signed = false);
};
}

View File

@ -180,6 +180,19 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
return arguments[0] / arguments[1];
else if (n == "mod")
return z3::mod(arguments[0], arguments[1]);
else if (n == "bvand")
return arguments[0] & arguments[1];
else if (n == "int2bv")
{
size_t size = std::stoi(_expr.arguments[1].name);
return z3::int2bv(size, arguments[0]);
}
else if (n == "bv2int")
{
auto intSort = dynamic_pointer_cast<IntSort>(_expr.sort);
smtAssert(intSort, "");
return z3::bv2int(arguments[0], intSort->isSigned);
}
else if (n == "select")
return z3::select(arguments[0], arguments[1]);
else if (n == "store")
@ -194,7 +207,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
}
else if (n == "tuple_get")
{
size_t index = std::stoi(_expr.arguments[1].name);
size_t index = stoul(_expr.arguments[1].name);
return z3::func_decl(m_context, Z3_get_tuple_sort_field_decl(m_context, z3Sort(*_expr.arguments[0].sort), index))(arguments[0]);
}
else if (n == "tuple_constructor")

View File

@ -693,14 +693,6 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
return size_t(-1);
}
else if (!var || !type(*var)->isValueType() || (
dynamic_cast<Literal const*>(var->value().get()) == nullptr &&
type(*var->value())->category() != Type::Category::RationalNumber
))
{
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
return size_t(-1);
}
else if (_context == yul::IdentifierContext::LValue)
{
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
@ -711,7 +703,26 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
return size_t(-1);
}
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
{
m_errorReporter.typeError(
2249_error,
_identifier.location,
"Constant variables with non-literal values cannot be forward referenced from inline assembly."
);
return size_t(-1);
}
else if (!var || !type(*var)->isValueType() || (
!dynamic_cast<Literal const*>(var->value().get()) &&
type(*var->value())->category() != Type::Category::RationalNumber
))
{
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
return size_t(-1);
}
}
solAssert(!dynamic_cast<FixedPointType const*>(var->type()), "FixedPointType not implemented.");
if (requiresStorage)
{
@ -2983,7 +2994,11 @@ bool TypeChecker::visit(Identifier const& _identifier)
if (!annotation.referencedDeclaration)
{
annotation.overloadedDeclarations = cleanOverloadedDeclarations(_identifier, annotation.candidateDeclarations);
if (!annotation.arguments)
if (annotation.overloadedDeclarations.empty())
m_errorReporter.fatalTypeError(7593_error, _identifier.location(), "No candidates for overload resolution found.");
else if (annotation.overloadedDeclarations.size() == 1)
annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
else if (!annotation.arguments)
{
// The identifier should be a public state variable shadowing other functions
vector<Declaration const*> candidates;
@ -3000,10 +3015,6 @@ bool TypeChecker::visit(Identifier const& _identifier)
else
m_errorReporter.fatalTypeError(7589_error, _identifier.location(), "No unique declaration found after variable lookup.");
}
else if (annotation.overloadedDeclarations.empty())
m_errorReporter.fatalTypeError(7593_error, _identifier.location(), "No candidates for overload resolution found.");
else if (annotation.overloadedDeclarations.size() == 1)
annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
else
{
vector<Declaration const*> candidates;

View File

@ -172,8 +172,7 @@ void StorageOffsets::computeOffsets(TypePointers const& _types)
++slotOffset;
byteOffset = 0;
}
if (slotOffset >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << util::errinfo_comment("Object too large for storage."));
solAssert(slotOffset < bigint(1) << 256 ,"Object too large for storage.");
offsets[i] = make_pair(u256(slotOffset), byteOffset);
solAssert(type->storageSize() >= 1, "Invalid storage size.");
if (type->storageSize() == 1 && byteOffset + type->storageBytes() <= 32)
@ -186,8 +185,7 @@ void StorageOffsets::computeOffsets(TypePointers const& _types)
}
if (byteOffset > 0)
++slotOffset;
if (slotOffset >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << util::errinfo_comment("Object too large for storage."));
solAssert(slotOffset < bigint(1) << 256, "Object too large for storage.");
m_storageSize = u256(slotOffset);
swap(m_offsets, offsets);
}
@ -1776,8 +1774,7 @@ u256 ArrayType::storageSize() const
}
else
size = bigint(length()) * baseType()->storageSize();
if (size >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << util::errinfo_comment("Array too large for storage."));
solAssert(size < bigint(1) << 256, "Array too large for storage.");
return max<u256>(1, u256(size));
}

View File

@ -422,7 +422,12 @@ void CompilerContext::appendInlineAssembly(
ErrorReporter errorReporter(errors);
auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(_assembly, "--CODEGEN--"));
yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
shared_ptr<yul::Block> parserResult = yul::Parser(errorReporter, dialect).parse(scanner, false);
optional<langutil::SourceLocation> locationOverride;
if (!_system)
locationOverride = m_asm->currentSourceLocation();
shared_ptr<yul::Block> parserResult =
yul::Parser(errorReporter, dialect, std::move(locationOverride))
.parse(scanner, false);
#ifdef SOL_OUTPUT_ASM
cout << yul::AsmPrinter(&dialect)(*parserResult) << endl;
#endif

View File

@ -701,7 +701,7 @@ vector<smtutil::SortPointer> CHC::stateSorts(ContractDefinition const& _contract
smtutil::SortPointer CHC::constructorSort()
{
return make_shared<smtutil::FunctionSort>(
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + m_stateSorts,
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts,
smtutil::SortProvider::boolSort
);
}
@ -747,7 +747,7 @@ smtutil::SortPointer CHC::sort(FunctionDefinition const& _function)
auto inputSorts = applyMap(_function.parameters(), smtSort);
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
return make_shared<smtutil::FunctionSort>(
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts,
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts,
smtutil::SortProvider::boolSort
);
}
@ -776,7 +776,7 @@ smtutil::SortPointer CHC::summarySort(FunctionDefinition const& _function, Contr
auto inputSorts = applyMap(_function.parameters(), smtSort);
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
return make_shared<smtutil::FunctionSort>(
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + sorts + inputSorts + sorts + outputSorts,
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + sorts + inputSorts + sorts + outputSorts,
smtutil::SortProvider::boolSort
);
}

View File

@ -274,6 +274,20 @@ bool SMTEncoder::visit(InlineAssembly const& _inlineAsm)
return false;
}
bool SMTEncoder::visit(TryCatchClause const& _clause)
{
if (auto params = _clause.parameters())
for (auto const& var: params->parameters())
createVariable(*var);
m_errorReporter.warning(
7645_error,
_clause.location(),
"Assertion checker does not support try/catch clauses."
);
return false;
}
bool SMTEncoder::visit(IfStatement const& _node)
{
_node.condition().accept(*this);
@ -361,7 +375,12 @@ void SMTEncoder::endVisit(Assignment const& _assignment)
else if (!smt::isSupportedType(_assignment.annotation().type->category()))
{
// Give it a new index anyway to keep the SSA scheme sound.
if (auto varDecl = identifierToVariable(_assignment.leftHandSide()))
Expression const* base = &_assignment.leftHandSide();
if (auto const* indexAccess = dynamic_cast<IndexAccess const*>(base))
base = leftmostBase(*indexAccess);
if (auto varDecl = identifierToVariable(*base))
m_context.newValue(*varDecl);
}
else
@ -463,9 +482,6 @@ void SMTEncoder::endVisit(UnaryOperation const& _op)
createExpr(_op);
if (_op.annotation().type->category() == Type::Category::FixedPoint)
return;
switch (_op.getOperator())
{
case Token::Not: // !
@ -477,8 +493,8 @@ void SMTEncoder::endVisit(UnaryOperation const& _op)
case Token::Inc: // ++ (pre- or postfix)
case Token::Dec: // -- (pre- or postfix)
{
solAssert(smt::isInteger(_op.annotation().type->category()), "");
auto cat = _op.annotation().type->category();
solAssert(smt::isInteger(cat) || smt::isFixedPoint(cat), "");
solAssert(_op.subExpression().annotation().willBeWrittenTo, "");
if (auto identifier = dynamic_cast<Identifier const*>(&_op.subExpression()))
{
@ -574,6 +590,8 @@ void SMTEncoder::endVisit(BinaryOperation const& _op)
arithmeticOperation(_op);
else if (TokenTraits::isCompareOp(_op.getOperator()))
compareOperation(_op);
else if (TokenTraits::isBitOp(_op.getOperator()))
bitwiseOperation(_op);
else
m_errorReporter.warning(
3876_error,
@ -1146,6 +1164,12 @@ void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression
}
else if (auto const* indexAccess = dynamic_cast<IndexAccess const*>(&_expr))
arrayIndexAssignment(*indexAccess, _array);
else if (dynamic_cast<MemberAccess const*>(&_expr))
m_errorReporter.warning(
9599_error,
_expr.location(),
"Assertion checker does not yet implement this expression."
);
else
solAssert(false, "");
}
@ -1346,6 +1370,43 @@ void SMTEncoder::booleanOperation(BinaryOperation const& _op)
);
}
void SMTEncoder::bitwiseOperation(BinaryOperation const& _op)
{
solAssert(TokenTraits::isBitOp(_op.getOperator()), "");
auto commonType = _op.annotation().commonType;
solAssert(commonType, "");
unsigned bvSize = 256;
bool isSigned = false;
if (auto const* intType = dynamic_cast<IntegerType const*>(commonType))
{
bvSize = intType->numBits();
isSigned = intType->isSigned();
}
else if (auto const* fixedType = dynamic_cast<FixedPointType const*>(commonType))
{
bvSize = fixedType->numBits();
isSigned = fixedType->isSigned();
}
auto bvLeft = smtutil::Expression::int2bv(expr(_op.leftExpression()), bvSize);
auto bvRight = smtutil::Expression::int2bv(expr(_op.rightExpression()), bvSize);
optional<smtutil::Expression> result;
if (_op.getOperator() == Token::BitAnd)
result = bvLeft & bvRight;
// TODO implement the other operators
else
m_errorReporter.warning(
1093_error,
_op.location(),
"Assertion checker does not yet implement this bitwise operator."
);
if (result)
defineExpr(_op, smtutil::Expression::bv2int(*result, isSigned));
}
smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Expression _right, IntegerType const& _type)
{
// Signed division in SMTLIB2 rounds differently for negative division.
@ -1755,7 +1816,6 @@ Expression const* SMTEncoder::leftmostBase(IndexAccess const& _indexAccess)
set<VariableDeclaration const*> SMTEncoder::touchedVariables(ASTNode const& _node)
{
solAssert(!m_callStack.empty(), "");
vector<CallableDeclaration const*> callStack;
for (auto const& call: m_callStack)
callStack.push_back(call.first);

View File

@ -91,6 +91,7 @@ protected:
bool visit(InlineAssembly const& _node) override;
void endVisit(Break const&) override {}
void endVisit(Continue const&) override {}
bool visit(TryCatchClause const& _node) override;
/// Do not visit subtree if node is a RationalNumber.
/// Symbolic _expr is the rational literal.
@ -108,6 +109,7 @@ protected:
);
void compareOperation(BinaryOperation const& _op);
void booleanOperation(BinaryOperation const& _op);
void bitwiseOperation(BinaryOperation const& _op);
void initContract(ContractDefinition const& _contract);
void initFunction(FunctionDefinition const& _function);

View File

@ -63,7 +63,7 @@ private:
/// Symbolic balances.
SymbolicArrayVariable m_balances{
std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::intSort, smtutil::SortProvider::intSort),
std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::uintSort, smtutil::SortProvider::uintSort),
"balances",
m_context
};

View File

@ -34,7 +34,11 @@ SortPointer smtSort(frontend::Type const& _type)
switch (smtKind(_type.category()))
{
case Kind::Int:
return SortProvider::intSort;
if (auto const* intType = dynamic_cast<IntegerType const*>(&_type))
return SortProvider::intSort(intType->isSigned());
if (auto const* fixedType = dynamic_cast<FixedPointType const*>(&_type))
return SortProvider::intSort(fixedType->isSigned());
return SortProvider::uintSort;
case Kind::Bool:
return SortProvider::boolSort;
case Kind::Function:
@ -50,7 +54,7 @@ SortPointer smtSort(frontend::Type const& _type)
returnSort = SortProvider::boolSort;
else if (returnTypes.size() > 1)
// Abstract sort.
returnSort = SortProvider::intSort;
returnSort = SortProvider::uintSort;
else
returnSort = smtSort(*returnTypes.front());
return make_shared<FunctionSort>(parameterSorts, returnSort);
@ -68,7 +72,7 @@ SortPointer smtSort(frontend::Type const& _type)
{
auto stringLitType = dynamic_cast<frontend::StringLiteralType const*>(&_type);
solAssert(stringLitType, "");
array = make_shared<ArraySort>(SortProvider::intSort, SortProvider::intSort);
array = make_shared<ArraySort>(SortProvider::uintSort, SortProvider::uintSort);
}
else
{
@ -81,7 +85,7 @@ SortPointer smtSort(frontend::Type const& _type)
solAssert(false, "");
solAssert(arrayType, "");
array = make_shared<ArraySort>(SortProvider::intSort, smtSortAbstractFunction(*arrayType->baseType()));
array = make_shared<ArraySort>(SortProvider::uintSort, smtSortAbstractFunction(*arrayType->baseType()));
}
string tupleName;
@ -98,7 +102,7 @@ SortPointer smtSort(frontend::Type const& _type)
return make_shared<TupleSort>(
tupleName,
vector<string>{tupleName + "_accessor_array", tupleName + "_accessor_length"},
vector<SortPointer>{array, SortProvider::intSort}
vector<SortPointer>{array, SortProvider::uintSort}
);
}
case Kind::Tuple:
@ -118,7 +122,7 @@ SortPointer smtSort(frontend::Type const& _type)
}
default:
// Abstract case.
return SortProvider::intSort;
return SortProvider::uintSort;
}
}
@ -133,7 +137,7 @@ vector<SortPointer> smtSort(vector<frontend::TypePointer> const& _types)
SortPointer smtSortAbstractFunction(frontend::Type const& _type)
{
if (isFunction(_type.category()))
return SortProvider::intSort;
return SortProvider::uintSort;
return smtSort(_type);
}
@ -144,7 +148,7 @@ vector<SortPointer> smtSortAbstractFunction(vector<frontend::TypePointer> const&
if (type)
sorts.push_back(smtSortAbstractFunction(*type));
else
sorts.push_back(SortProvider::intSort);
sorts.push_back(SortProvider::uintSort);
return sorts;
}
@ -220,6 +224,8 @@ pair<bool, shared_ptr<SymbolicVariable>> newSymbolicVariable(
}
else if (isInteger(_type.category()))
var = make_shared<SymbolicIntVariable>(type, type, _uniqueName, _context);
else if (isFixedPoint(_type.category()))
var = make_shared<SymbolicIntVariable>(type, type, _uniqueName, _context);
else if (isFixedBytes(_type.category()))
{
auto fixedBytesType = dynamic_cast<frontend::FixedBytesType const*>(type);
@ -268,6 +274,11 @@ bool isInteger(frontend::Type::Category _category)
return _category == frontend::Type::Category::Integer;
}
bool isFixedPoint(frontend::Type::Category _category)
{
return _category == frontend::Type::Category::FixedPoint;
}
bool isRational(frontend::Type::Category _category)
{
return _category == frontend::Type::Category::RationalNumber;
@ -296,6 +307,7 @@ bool isEnum(frontend::Type::Category _category)
bool isNumber(frontend::Type::Category _category)
{
return isInteger(_category) ||
isFixedPoint(_category) ||
isRational(_category) ||
isFixedBytes(_category) ||
isAddress(_category) ||

View File

@ -43,6 +43,7 @@ bool isSupportedTypeDeclaration(frontend::Type::Category _category);
bool isSupportedTypeDeclaration(frontend::Type const& _type);
bool isInteger(frontend::Type::Category _category);
bool isFixedPoint(frontend::Type::Category _category);
bool isRational(frontend::Type::Category _category);
bool isFixedBytes(frontend::Type::Category _category);
bool isAddress(frontend::Type::Category _category);

View File

@ -286,7 +286,7 @@ SymbolicArrayVariable::SymbolicArrayVariable(
std::make_shared<TupleSort>(
"array_length_pair",
std::vector<std::string>{"array", "length"},
std::vector<SortPointer>{m_sort, SortProvider::intSort}
std::vector<SortPointer>{m_sort, SortProvider::uintSort}
),
m_uniqueName + "_array_length_pair",
m_context

View File

@ -33,6 +33,7 @@ set<VariableDeclaration const*> VariableUsage::touchedVariables(ASTNode const& _
m_touchedVariables.clear();
m_callStack.clear();
m_callStack += _outerCallstack;
if (!m_callStack.empty())
m_lastCall = m_callStack.back();
_node.accept(*this);
return m_touchedVariables;
@ -103,8 +104,7 @@ void VariableUsage::checkIdentifier(Identifier const& _identifier)
solAssert(declaration, "");
if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
{
solAssert(m_lastCall, "");
if (!varDecl->isLocalVariable() || varDecl->functionOrModifierDefinition() == m_lastCall)
if (!varDecl->isLocalVariable() || (m_lastCall && varDecl->functionOrModifierDefinition() == m_lastCall))
m_touchedVariables.insert(varDecl);
}
}

View File

@ -53,6 +53,9 @@ string solidity::util::toHex(uint8_t _data, HexCase _case)
string solidity::util::toHex(bytes const& _data, HexPrefix _prefix, HexCase _case)
{
if (_data.empty())
return {};
std::string ret(_data.size() * 2 + (_prefix == HexPrefix::Add ? 2 : 0), 0);
size_t i = 0;
@ -64,15 +67,15 @@ string solidity::util::toHex(bytes const& _data, HexPrefix _prefix, HexCase _cas
// Mixed case will be handled inside the loop.
char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars;
int rix = _data.size() - 1;
size_t rix = _data.size() - 1;
for (uint8_t c: _data)
{
// switch hex case every four hexchars
if (_case == HexCase::Mixed)
chars = (rix-- & 2) == 0 ? lowerHexChars : upperHexChars;
ret[i++] = chars[(unsigned(c) / 16) & 0xf];
ret[i++] = chars[unsigned(c) & 0xf];
ret[i++] = chars[(static_cast<size_t>(c) >> 4ul) & 0xfu];
ret[i++] = chars[c & 0xfu];
}
assertThrow(i == ret.size(), Exception, "");
@ -95,6 +98,9 @@ int solidity::util::fromHex(char _i, WhenError _throw)
bytes solidity::util::fromHex(std::string const& _s, WhenError _throw)
{
if (_s.empty())
return {};
unsigned s = (_s.size() >= 2 && _s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
ret.reserve((_s.size() - s + 1) / 2);

View File

@ -42,7 +42,7 @@
template <class T, class U> std::vector<T>& operator+=(std::vector<T>& _a, U& _b)
{
for (auto const& i: _b)
_a.push_back(i);
_a.push_back(T(i));
return _a;
}
/// Concatenate the contents of a container onto a vector, move variant.
@ -299,7 +299,7 @@ template <class T>
inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
{
static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift
int i = 0;
unsigned i = 0;
for (T v = _val; v; ++i, v >>= 8) {}
bytes ret(std::max<unsigned>(_min, i), 0);
toBigEndian(_val, ret);
@ -379,7 +379,7 @@ void iterateReplacing(std::vector<T>& _vector, F const& _f)
{
if (!useModified)
{
std::move(_vector.begin(), _vector.begin() + i, back_inserter(modifiedVector));
std::move(_vector.begin(), _vector.begin() + ptrdiff_t(i), back_inserter(modifiedVector));
useModified = true;
}
modifiedVector += std::move(*r);
@ -406,7 +406,7 @@ void iterateReplacingWindow(std::vector<T>& _vector, F const& _f, std::index_seq
{
if (!useModified)
{
std::move(_vector.begin(), _vector.begin() + i, back_inserter(modifiedVector));
std::move(_vector.begin(), _vector.begin() + ptrdiff_t(i), back_inserter(modifiedVector));
useModified = true;
}
modifiedVector += std::move(*r);

View File

@ -56,7 +56,7 @@ inline T readFile(std::string const& _file)
return ret; // do not read empty file (MSVC does not like it)
is.seekg(0, is.beg);
ret.resize((length + c_elementSize - 1) / c_elementSize);
ret.resize((static_cast<size_t>(length) + c_elementSize - 1) / c_elementSize);
is.read(const_cast<char*>(reinterpret_cast<char const*>(ret.data())), length);
return ret;
}
@ -107,8 +107,8 @@ public:
DisableConsoleBuffering()
{
tcgetattr(0, &m_termios);
m_termios.c_lflag &= ~ICANON;
m_termios.c_lflag &= ~ECHO;
m_termios.c_lflag &= ~tcflag_t(ICANON);
m_termios.c_lflag &= ~tcflag_t(ECHO);
m_termios.c_cc[VMIN] = 1;
m_termios.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &m_termios);

View File

@ -62,7 +62,7 @@ string base58Encode(bytes const& _data)
string output;
while (data)
{
output += alphabet[size_t(data % alphabet.size())];
output += alphabet[static_cast<size_t>(data % alphabet.size())];
data /= alphabet.size();
}
reverse(output.begin(), output.end());

View File

@ -156,14 +156,14 @@ inline std::string formatNumberReadable(
if (_useTruncation)
{
// return as interior-truncated hex.
int len = str.size();
size_t len = str.size();
if (len < 24)
return str;
int const initialChars = (prefix == HexPrefix::Add) ? 6 : 4;
int const finalChars = 4;
int numSkipped = len - initialChars - finalChars;
size_t const initialChars = (prefix == HexPrefix::Add) ? 6 : 4;
size_t const finalChars = 4;
size_t numSkipped = len - initialChars - finalChars;
return str.substr(0, initialChars) +
"...{+" +

View File

@ -138,13 +138,4 @@ bool validateUTF8(std::string const& _input, size_t& _invalidPosition)
return validateUTF8(reinterpret_cast<unsigned char const*>(_input.c_str()), _input.length(), _invalidPosition);
}
size_t numCodepoints(std::string const& _utf8EncodedInput)
{
size_t codepoint = 0;
for (char c: _utf8EncodedInput)
codepoint += (c & 0xc0) != 0x80;
return codepoint;
}
}

View File

@ -38,6 +38,4 @@ inline bool validateUTF8(std::string const& _input)
return validateUTF8(_input, invalidPos);
}
size_t numCodepoints(std::string const& _utf8EncodedInput);
}

View File

@ -95,10 +95,10 @@ void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last) {
word_t w[64];
std::fill(w, w + 64, 0);
for (std::size_t i = 0; i < 16; ++i) {
w[i] = (static_cast<word_t>(mask_8bit(*(first + i * 4))) << 24) |
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 1))) << 16) |
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 2))) << 8) |
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 3))));
w[i] = (static_cast<word_t>(mask_8bit(*(first + long(i) * 4))) << 24) |
(static_cast<word_t>(mask_8bit(*(first + long(i) * 4 + 1))) << 16) |
(static_cast<word_t>(mask_8bit(*(first + long(i) * 4 + 2))) << 8) |
(static_cast<word_t>(mask_8bit(*(first + long(i) * 4 + 3))));
}
for (std::size_t i = 16; i < 64; ++i) {
w[i] = mask_32bit(ssig1(w[i - 2]) + w[i - 7] + ssig0(w[i - 15]) +
@ -196,10 +196,10 @@ class hash256_one_by_one {
std::copy(first, last, std::back_inserter(buffer_));
std::size_t i = 0;
for (; i + 64 <= buffer_.size(); i += 64) {
detail::hash256_block(h_, buffer_.begin() + i,
buffer_.begin() + i + 64);
detail::hash256_block(h_, buffer_.begin() + long(i),
buffer_.begin() + long(i) + 64);
}
buffer_.erase(buffer_.begin(), buffer_.begin() + i);
buffer_.erase(buffer_.begin(), buffer_.begin() + long(i));
}
void finish() {
@ -297,20 +297,20 @@ void hash256_impl(RaIter first, RaIter last, OutIter first2, OutIter last2, int,
template <typename InputIter, typename OutIter>
void hash256_impl(InputIter first, InputIter last, OutIter first2,
OutIter last2, int buffer_size, std::input_iterator_tag) {
OutIter last2, size_t buffer_size, std::input_iterator_tag) {
std::vector<byte_t> buffer(buffer_size);
hash256_one_by_one hasher;
// hasher.init();
while (first != last) {
int size = buffer_size;
for (int i = 0; i != buffer_size; ++i, ++first) {
size_t size = buffer_size;
for (size_t i = 0; i != buffer_size; ++i, ++first) {
if (first == last) {
size = i;
break;
}
buffer[i] = *first;
}
hasher.process(buffer.begin(), buffer.begin() + size);
hasher.process(buffer.begin(), buffer.begin() + ptrdiff_t(size));
}
hasher.finish();
hasher.get_hash_bytes(first2, last2);

View File

@ -81,17 +81,19 @@ vector<YulString> AsmAnalyzer::operator()(Literal const& _literal)
{
expectValidType(_literal.type, _literal.location);
if (_literal.kind == LiteralKind::String && _literal.value.str().size() > 32)
typeError(
m_errorReporter.typeError(
3069_error,
_literal.location,
"String literal too long (" + to_string(_literal.value.str().size()) + " > 32)"
);
else if (_literal.kind == LiteralKind::Number && bigint(_literal.value.str()) > u256(-1))
typeError(_literal.location, "Number literal too large (> 256 bits)");
m_errorReporter.typeError(6708_error, _literal.location, "Number literal too large (> 256 bits)");
else if (_literal.kind == LiteralKind::Boolean)
yulAssert(_literal.value == "true"_yulstring || _literal.value == "false"_yulstring, "");
if (!m_dialect.validTypeForLiteral(_literal.kind, _literal.value, _literal.type))
typeError(
m_errorReporter.typeError(
5170_error,
_literal.location,
"Invalid type \"" + _literal.type.str() + "\" for literal \"" + _literal.value.str() + "\"."
);
@ -110,7 +112,8 @@ vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
[&](Scope::Variable const& _var)
{
if (!m_activeVariables.count(&_var))
declarationError(
m_errorReporter.declarationError(
4990_error,
_identifier.location,
"Variable " + _identifier.name.str() + " used before it was declared."
);
@ -118,7 +121,8 @@ vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
},
[&](Scope::Function const&)
{
typeError(
m_errorReporter.typeError(
6041_error,
_identifier.location,
"Function " + _identifier.name.str() + " used without being called."
);
@ -141,7 +145,7 @@ vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
}
if (!found && watcher.ok())
// Only add an error message if the callback did not do it.
declarationError(_identifier.location, "Identifier not found.");
m_errorReporter.declarationError(8198_error, _identifier.location, "Identifier not found.");
}
return {type};
@ -152,7 +156,9 @@ void AsmAnalyzer::operator()(ExpressionStatement const& _statement)
auto watcher = m_errorReporter.errorWatcher();
vector<YulString> types = std::visit(*this, _statement.expression);
if (watcher.ok() && !types.empty())
typeError(_statement.location,
m_errorReporter.typeError(
3083_error,
_statement.location,
"Top-level expressions are not supposed to return values (this expression returns " +
to_string(types.size()) +
" value" +
@ -170,7 +176,8 @@ void AsmAnalyzer::operator()(Assignment const& _assignment)
vector<YulString> types = std::visit(*this, *_assignment.value);
if (types.size() != numVariables)
declarationError(
m_errorReporter.declarationError(
8678_error,
_assignment.location,
"Variable count does not match number of values (" +
to_string(numVariables) +
@ -202,7 +209,9 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
{
vector<YulString> types = std::visit(*this, *_varDecl.value);
if (types.size() != numVariables)
declarationError(_varDecl.location,
m_errorReporter.declarationError(
3812_error,
_varDecl.location,
"Variable count mismatch: " +
to_string(numVariables) +
" variables and " +
@ -217,7 +226,8 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
givenType = types[i];
TypedName const& variable = _varDecl.variables[i];
if (variable.type != givenType)
typeError(
m_errorReporter.typeError(
3947_error,
variable.location,
"Assigning value of type \"" + givenType.str() + "\" to variable of type \"" + variable.type.str() + "."
);
@ -265,7 +275,8 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
else if (!m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
[&](Scope::Variable const&)
{
typeError(
m_errorReporter.typeError(
4202_error,
_funCall.functionName.location,
"Attempt to call variable instead of function."
);
@ -278,12 +289,13 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
}))
{
if (!warnOnInstructions(_funCall))
declarationError(_funCall.functionName.location, "Function not found.");
m_errorReporter.declarationError(4619_error, _funCall.functionName.location, "Function not found.");
yulAssert(!watcher.ok(), "Expected a reported error.");
}
if (parameterTypes && _funCall.arguments.size() != parameterTypes->size())
typeError(
m_errorReporter.typeError(
7000_error,
_funCall.functionName.location,
"Function expects " +
to_string(parameterTypes->size()) +
@ -301,7 +313,8 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
if (needsLiteralArguments && (*needsLiteralArguments)[i - 1])
{
if (!holds_alternative<Literal>(arg))
typeError(
m_errorReporter.typeError(
9114_error,
_funCall.functionName.location,
"Function expects direct literals as arguments."
);
@ -310,7 +323,8 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
_funCall.functionName.name.str() == "dataoffset"
)
if (!m_dataNames.count(std::get<Literal>(arg).value))
typeError(
m_errorReporter.typeError(
3517_error,
_funCall.functionName.location,
"Unknown data object \"" + std::get<Literal>(arg).value.str() + "\"."
);
@ -362,7 +376,7 @@ void AsmAnalyzer::operator()(Switch const& _switch)
/// Note: the parser ensures there is only one default case
if (watcher.ok() && !cases.insert(valueOfLiteral(*_case.value)).second)
declarationError(_case.location, "Duplicate case defined.");
m_errorReporter.declarationError(6792_error, _case.location, "Duplicate case defined.");
}
(*this)(_case.body);
@ -408,7 +422,8 @@ YulString AsmAnalyzer::expectExpression(Expression const& _expr)
{
vector<YulString> types = std::visit(*this, _expr);
if (types.size() != 1)
typeError(
m_errorReporter.typeError(
3950_error,
locationOf(_expr),
"Expected expression to evaluate to one value, but got " +
to_string(types.size()) +
@ -421,7 +436,9 @@ void AsmAnalyzer::expectBoolExpression(Expression const& _expr)
{
YulString type = expectExpression(_expr);
if (type != m_dialect.boolType)
typeError(locationOf(_expr),
m_errorReporter.typeError(
1733_error,
locationOf(_expr),
"Expected a value of boolean type \"" +
m_dialect.boolType.str() +
"\" but got \"" +
@ -440,9 +457,10 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT
{
// Check that it is a variable
if (!holds_alternative<Scope::Variable>(*var))
typeError(_variable.location, "Assignment requires variable.");
m_errorReporter.typeError(2657_error, _variable.location, "Assignment requires variable.");
else if (!m_activeVariables.count(&std::get<Scope::Variable>(*var)))
declarationError(
m_errorReporter.declarationError(
1133_error,
_variable.location,
"Variable " + _variable.name.str() + " used before it was declared."
);
@ -464,9 +482,11 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT
if (!found && watcher.ok())
// Only add message if the callback did not.
declarationError(_variable.location, "Variable not found or variable not lvalue.");
m_errorReporter.declarationError(4634_error, _variable.location, "Variable not found or variable not lvalue.");
if (variableType && *variableType != _valueType)
typeError(_variable.location,
m_errorReporter.typeError(
9547_error,
_variable.location,
"Assigning a value of type \"" +
_valueType.str() +
"\" to a variable of type \"" +
@ -488,7 +508,8 @@ Scope& AsmAnalyzer::scope(Block const* _block)
void AsmAnalyzer::expectValidType(YulString _type, SourceLocation const& _location)
{
if (!m_dialect.types.count(_type))
typeError(
m_errorReporter.typeError(
5473_error,
_location,
"\"" + _type.str() + "\" is not a valid type (user defined types are not yet supported)."
);
@ -497,7 +518,9 @@ void AsmAnalyzer::expectValidType(YulString _type, SourceLocation const& _locati
void AsmAnalyzer::expectType(YulString _expectedType, YulString _givenType, SourceLocation const& _location)
{
if (_expectedType != _givenType)
typeError(_location,
m_errorReporter.typeError(
3781_error,
_location,
"Expected a value of type \"" +
_expectedType.str() +
"\" but got \"" +
@ -524,7 +547,8 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation
yulAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), "");
auto errorForVM = [&](string const& vmKindMessage) {
typeError(
m_errorReporter.typeError(
7079_error,
_location,
"The \"" +
boost::to_lower_copy(instructionInfo(_instr).name)
@ -584,13 +608,3 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation
return true;
}
void AsmAnalyzer::typeError(SourceLocation const& _location, string const& _description)
{
m_errorReporter.typeError(7569_error, _location, _description);
}
void AsmAnalyzer::declarationError(SourceLocation const& _location, string const& _description)
{
m_errorReporter.declarationError(9595_error, _location, _description);
}

View File

@ -117,9 +117,6 @@ private:
return warnOnInstructions(_functionCall.functionName.name.str(), _functionCall.functionName.location);
}
void typeError(langutil::SourceLocation const& _location, std::string const& _description);
void declarationError(langutil::SourceLocation const& _location, std::string const& _description);
yul::ExternalIdentifierAccess::Resolver m_resolver;
Scope* m_currentScope = nullptr;
/// Variables that are active at the current point in assembly (as opposed to

View File

@ -46,8 +46,15 @@ public:
None, ForLoopPre, ForLoopPost, ForLoopBody
};
explicit Parser(langutil::ErrorReporter& _errorReporter, Dialect const& _dialect):
ParserBase(_errorReporter), m_dialect(_dialect) {}
explicit Parser(
langutil::ErrorReporter& _errorReporter,
Dialect const& _dialect,
std::optional<langutil::SourceLocation> _locationOverride = {}
):
ParserBase(_errorReporter),
m_dialect(_dialect),
m_locationOverride(std::move(_locationOverride))
{}
/// Parses an inline assembly block starting with `{` and ending with `}`.
/// @param _reuseScanner if true, do check for end of input after the `}`.
@ -60,6 +67,11 @@ public:
protected:
using ElementaryOperation = std::variant<Literal, Identifier, FunctionCall>;
langutil::SourceLocation currentLocation() const override
{
return m_locationOverride ? *m_locationOverride : ParserBase::currentLocation();
}
/// Creates an inline assembly node with the current source location.
template <class T> T createWithLocation() const
{
@ -91,6 +103,7 @@ protected:
private:
Dialect const& m_dialect;
std::optional<langutil::SourceLocation> m_locationOverride;
ForLoopComponent m_currentForLoopComponent = ForLoopComponent::None;
bool m_insideFunction = false;
};

View File

@ -39,6 +39,18 @@ bytes toBytes(uint8_t _b)
return bytes(1, _b);
}
enum class LimitsKind: uint8_t
{
Min = 0x00,
MinMax = 0x01,
};
enum class Mutability: uint8_t
{
Const = 0x00,
Var = 0x01,
};
enum class Section: uint8_t
{
CUSTOM = 0x00,
@ -530,8 +542,8 @@ bytes BinaryTransform::functionSection(vector<FunctionDefinition> const& _functi
bytes BinaryTransform::memorySection()
{
bytes result = lebEncode(1);
result.push_back(0); // flags
result.push_back(1); // initial
result.push_back(static_cast<uint8_t>(LimitsKind::Min));
result.push_back(1); // initial length
return makeSection(Section::MEMORY, std::move(result));
}
@ -540,8 +552,8 @@ bytes BinaryTransform::globalSection()
bytes result = lebEncode(m_globals.size());
for (size_t i = 0; i < m_globals.size(); ++i)
result +=
// mutable i64
bytes{uint8_t(ValueType::I64), 1} +
toBytes(ValueType::I64) +
lebEncode(static_cast<uint8_t>(Mutability::Var)) +
toBytes(Opcode::I64Const) +
lebEncodeSigned(0) +
toBytes(Opcode::End);

View File

@ -1,6 +1,9 @@
#! /usr/bin/env python3
import random
import re
import os
import getopt
import sys
from os import path
ENCODING = "utf-8"
@ -115,19 +118,19 @@ def find_source_files(top_dir):
return source_file_names
def main():
def main(argv):
check_only = False
noconfirm = False
opts, args = getopt.getopt(argv, "", ["check-only", "noconfirm"])
for opt, arg in opts:
if opt == '--check-only':
check_only = True
elif opt == '--noconfirm':
noconfirm = True
random.seed()
cwd = os.getcwd()
answer = input(
f"This script checks and corrects *_error literals in .h and .cpp files\n"
f"in {cwd}, recursively.\n\n"
f"Please commit current changes first, and review the results when the script finishes.\n\n"
f"Do you want to start [Y/N]? "
)
while len(answer) == 0 or answer not in "YNyn":
answer = input("[Y/N]? ")
if answer not in "yY":
return
source_file_names = find_source_files(cwd)
@ -147,10 +150,26 @@ def main():
if ok:
print("No incorrect IDs found")
else:
exit(0)
if check_only:
exit(1)
if not noconfirm:
answer = input(
"\nDo you want to fix incorrect IDs?\n"
"Please commit current changes first, and review the results when the script finishes.\n"
"[Y/N]? "
)
while len(answer) == 0 or answer not in "YNyn":
answer = input("[Y/N]? ")
if answer not in "yY":
exit(1)
fix_ids(used_ids, source_file_names)
print("Fixing completed")
exit(2)
if __name__ == "__main__":
main()
main(sys.argv[1:])

View File

@ -107,6 +107,7 @@ std::ostream& serr(bool _used = true)
static string const g_stdinFileNameStr = "<stdin>";
static string const g_strAbi = "abi";
static string const g_strAllowPaths = "allow-paths";
static string const g_strBasePath = "base-path";
static string const g_strAsm = "asm";
static string const g_strAsmJson = "asm-json";
static string const g_strAssemble = "assemble";
@ -181,6 +182,7 @@ static string const g_strOldReporter = "old-reporter";
static string const g_argAbi = g_strAbi;
static string const g_argPrettyJson = g_strPrettyJson;
static string const g_argAllowPaths = g_strAllowPaths;
static string const g_argBasePath = g_strBasePath;
static string const g_argAsm = g_strAsm;
static string const g_argAsmJson = g_strAsmJson;
static string const g_argAssemble = g_strAssemble;
@ -629,8 +631,8 @@ bool CommandLineInterface::parseLibraryOption(string const& _input)
serr() << "Colon separator missing in library address specifier \"" << lib << "\"" << endl;
return false;
}
string libName(lib.begin(), lib.begin() + colon);
string addrString(lib.begin() + colon + 1, lib.end());
string libName(lib.begin(), lib.begin() + static_cast<ptrdiff_t>(colon));
string addrString(lib.begin() + static_cast<ptrdiff_t>(colon) + 1, lib.end());
boost::trim(libName);
boost::trim(addrString);
if (addrString.substr(0, 2) == "0x")
@ -832,6 +834,11 @@ Allowed options)").c_str(),
po::value<string>()->value_name("path(s)"),
"Allow a given path for imports. A list of paths can be supplied by separating them with a comma."
)
(
g_argBasePath.c_str(),
po::value<string>()->value_name("path"),
"Use the given path as the root of the source tree instead of the root of the filesystem."
)
(g_argColor.c_str(), "Force colored output.")
(g_argNoColor.c_str(), "Explicitly disable colored output, disabling terminal auto-detection.")
(g_argOldReporter.c_str(), "Enables old diagnostics reporter.")
@ -967,7 +974,8 @@ bool CommandLineInterface::processInput()
string validPath = _path;
if (validPath.find("file://") == 0)
validPath.erase(0, 7);
auto path = boost::filesystem::path(validPath);
auto const path = m_basePath / validPath;
auto canonicalPath = boost::filesystem::weakly_canonical(path);
bool isAllowed = false;
for (auto const& allowedDir: m_allowedDirectories)
@ -1005,6 +1013,19 @@ bool CommandLineInterface::processInput()
}
};
if (m_args.count(g_argBasePath))
{
boost::filesystem::path const fspath{m_args[g_argBasePath].as<string>()};
if (!boost::filesystem::is_directory(fspath))
{
serr() << "Base path must be a directory: \"" << fspath << "\"\n";
return false;
}
m_basePath = fspath;
if (!contains(m_allowedDirectories, fspath))
m_allowedDirectories.push_back(fspath);
}
if (m_args.count(g_argAllowPaths))
{
vector<string> paths;

View File

@ -117,6 +117,8 @@ private:
std::vector<frontend::CompilerStack::Remapping> m_remappings;
/// list of allowed directories to read files from
std::vector<boost::filesystem::path> m_allowedDirectories;
/// Base path, used for resolving relative paths in imports.
boost::filesystem::path m_basePath;
/// map of library names to addresses
std::map<std::string, util::h160> m_libraries;
/// Solidity compiler stack

View File

@ -116,11 +116,11 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix,
for (int i = error.locationStart; i < error.locationEnd; i++)
if (isWarning)
{
if (sourceFormatting[i] == formatting::RESET)
sourceFormatting[i] = formatting::ORANGE_BACKGROUND_256;
if (sourceFormatting[static_cast<size_t>(i)] == formatting::RESET)
sourceFormatting[static_cast<size_t>(i)] = formatting::ORANGE_BACKGROUND_256;
}
else
sourceFormatting[i] = formatting::RED_BACKGROUND;
sourceFormatting[static_cast<size_t>(i)] = formatting::RED_BACKGROUND;
}
_stream << _linePrefix << sourceFormatting.front() << source.front();

View File

@ -223,7 +223,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
if (message.kind == EVMC_CREATE || message.kind == EVMC_CREATE2)
{
result.gas_left -= evmasm::GasCosts::createDataGas * result.output_size;
result.gas_left -= static_cast<int64_t>(evmasm::GasCosts::createDataGas * result.output_size);
if (result.gas_left < 0)
{
result.gas_left = 0;

View File

@ -101,7 +101,9 @@ u256 ExecutionFramework::gasPrice() const
u256 ExecutionFramework::blockHash(u256 const& _number) const
{
return {EVMHost::convertFromEVMC(m_evmHost->get_block_hash(uint64_t(_number & numeric_limits<uint64_t>::max())))};
return {EVMHost::convertFromEVMC(
m_evmHost->get_block_hash(static_cast<int64_t>(_number & numeric_limits<uint64_t>::max()))
)};
}
u256 ExecutionFramework::blockNumber() const
@ -153,7 +155,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256
if (m_showMessages)
{
cout << " out: " << toHex(m_output) << endl;
cout << " result: " << size_t(result.status_code) << endl;
cout << " result: " << static_cast<size_t>(result.status_code) << endl;
cout << " gas used: " << m_gasUsed.str() << endl;
}
}
@ -180,7 +182,7 @@ void ExecutionFramework::sendEther(Address const& _addr, u256 const& _amount)
size_t ExecutionFramework::currentTimestamp()
{
return m_evmHost->tx_context.block_timestamp;
return static_cast<size_t>(m_evmHost->tx_context.block_timestamp);
}
size_t ExecutionFramework::blockTimestamp(u256 _block)
@ -188,7 +190,7 @@ size_t ExecutionFramework::blockTimestamp(u256 _block)
if (_block > blockNumber())
return 0;
else
return size_t((currentTimestamp() / blockNumber()) * _block);
return static_cast<size_t>((currentTimestamp() / blockNumber()) * _block);
}
Address ExecutionFramework::account(size_t _idx)

View File

@ -36,14 +36,14 @@ bytes onlyMetadata(bytes const& _bytecode)
unsigned size = _bytecode.size();
if (size < 5)
return bytes{};
size_t metadataSize = (_bytecode[size - 2] << 8) + _bytecode[size - 1];
size_t metadataSize = (static_cast<size_t>(_bytecode[size - 2]) << 8ul) + static_cast<size_t>(_bytecode[size - 1]);
if (size < (metadataSize + 2))
return bytes{};
// Sanity check: assume the first byte is a fixed-size CBOR array with 1, 2 or 3 entries
unsigned char firstByte = _bytecode[size - metadataSize - 2];
if (firstByte != 0xa1 && firstByte != 0xa2 && firstByte != 0xa3)
return bytes{};
return bytes(_bytecode.end() - metadataSize - 2, _bytecode.end() - 2);
return bytes(_bytecode.end() - static_cast<ptrdiff_t>(metadataSize) - 2, _bytecode.end() - 2);
}
bytes bytecodeSansMetadata(bytes const& _bytecode)

View File

@ -18,11 +18,13 @@
#include <test/Common.h>
#include <test/TestCase.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
#include <libsolutil/AnsiColorized.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <stdexcept>
#include <iostream>
#include <stdexcept>
using namespace std;
using namespace solidity;
@ -78,6 +80,33 @@ void TestCase::printIndented(ostream& _stream, string const& _output, string con
_stream << _linePrefix << line << endl;
}
void TestCase::printSource(ostream& _stream, string const& _linePrefix, bool const) const
{
printIndented(_stream, m_source, _linePrefix);
}
void TestCase::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
{
printIndented(_stream, m_obtainedResult, _linePrefix);
}
TestCase::TestResult TestCase::checkResult(std::ostream& _stream, const std::string& _linePrefix, bool const _formatted)
{
if (m_expectation != m_obtainedResult)
{
string nextIndentLevel = _linePrefix + " ";
util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::CYAN})
<< _linePrefix << "Expected result:" << endl;
// TODO could compute a simple diff with highlighted lines
printIndented(_stream, m_expectation, nextIndentLevel);
util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::CYAN})
<< _linePrefix << "Obtained result:" << endl;
printIndented(_stream, m_obtainedResult, nextIndentLevel);
return TestResult::Failure;
}
return TestResult::Success;
}
EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filename):
TestCase(_filename)
{

View File

@ -57,14 +57,14 @@ public:
/// Each line of output is prefixed with @arg _linePrefix.
/// If @arg _formatted is true, color-coding may be used to indicate
/// error locations in the contract, if applicable.
virtual void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false) const = 0;
virtual void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false) const;
/// Outputs settings.
virtual void printSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false);
/// Outputs updated settings
virtual void printUpdatedSettings(std::ostream& _stream, std::string const& _linePrefix = "");
/// Outputs test expectations to @arg _stream that match the actual results of the test.
/// Each line of output is prefixed with @arg _linePrefix.
virtual void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const = 0;
virtual void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const;
static bool isTestFilename(boost::filesystem::path const& _filename);
@ -97,6 +97,11 @@ protected:
}
void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const;
TestCase::TestResult checkResult(std::ostream& _stream, const std::string& _linePrefix, bool const _formatted);
std::string m_source;
std::string m_obtainedResult;
std::string m_expectation;
TestCaseReader m_reader;
bool m_shouldRun = true;

View File

@ -1,11 +0,0 @@
Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
--> message_format_utf16/input.sol
Warning: Source file does not specify required compiler version!
--> message_format_utf16/input.sol
Warning: Statement has no effect.
--> message_format_utf16/input.sol:2:58:
|
2 | /* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; }
| ^^^^^^^^^^^^

View File

@ -1,3 +0,0 @@
contract Foo {
/* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; }
}

View File

@ -0,0 +1,35 @@
Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.
--> message_format_utf8/input.sol
Warning: Source file does not specify required compiler version!
--> message_format_utf8/input.sol
Warning: Statement has no effect.
--> message_format_utf8/input.sol:2:58:
|
2 | /* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; }
| ^^^^^^^^^^^^
Warning: Statement has no effect.
--> message_format_utf8/input.sol:6:25:
|
6 | "S = π × r²";
| ^^^^^^^^^^^^
Warning: Statement has no effect.
--> message_format_utf8/input.sol:7:39:
|
7 | /* ₀₁₂₃₄⁵⁶⁷⁸⁹ */ "∑ 1/n! ≈ 2.7"; // tabs in-between
| ^^^^^^^^^^^^^^
Warning: Statement has no effect.
--> message_format_utf8/input.sol:8:30:
|
8 | /* Ŀŏŗėɯ ïƥŝʉɱ */ "μὴ χεῖρον βέλτιστον"; // tabs in-between and inside
| ^^^ ^^^^^^ ^^^^^^^^^^
Warning: Function state mutability can be restricted to pure
--> message_format_utf8/input.sol:12:2:
|
12 | function selector() public returns(uint) { // starts with tab
| ^ (Relevant source part starts here and spans across multiple lines).

View File

@ -0,0 +1,15 @@
contract Foo {
/* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; }
function f() public pure {
"S = π ×";
/* ₀₁₂₃₄⁵⁶⁷⁸⁹ */ "∑ 1/n! ≈ 2.7"; // tabs in-between
/* Ŀŏŗėɯ ïƥŝʉɱ */ "μὴ χεῖρον βέλτιστον"; // tabs in-between and inside
}
function selector() public returns(uint) { // starts with tab
return 0;
}
}

View File

@ -19,20 +19,14 @@ EVM assembly:
sstore
/* "optimizer_BlockDeDuplicator/input.sol":60:213 contract C {... */
callvalue
/* "--CODEGEN--":2:4 */
dup1
iszero
tag_5
jumpi
/* "--CODEGEN--":27:28 */
0x00
/* "--CODEGEN--":24:25 */
dup1
/* "--CODEGEN--":17:29 */
revert
/* "--CODEGEN--":2:4 */
tag_5:
/* "optimizer_BlockDeDuplicator/input.sol":60:213 contract C {... */
pop
jump(tag_6)
/* "optimizer_BlockDeDuplicator/input.sol":77:103 function fun_x() public {} */
@ -53,21 +47,14 @@ sub_0: assembly {
/* "optimizer_BlockDeDuplicator/input.sol":60:213 contract C {... */
mstore(0x40, 0x80)
callvalue
/* "--CODEGEN--":5:14 */
dup1
/* "--CODEGEN--":2:4 */
iszero
tag_1
jumpi
/* "--CODEGEN--":27:28 */
0x00
/* "--CODEGEN--":24:25 */
dup1
/* "--CODEGEN--":17:29 */
revert
/* "--CODEGEN--":2:4 */
tag_1:
/* "optimizer_BlockDeDuplicator/input.sol":60:213 contract C {... */
pop
jumpi(tag_2, lt(calldatasize, 0x04))
shr(0xe0, calldataload(0x00))
@ -87,11 +74,8 @@ sub_0: assembly {
tag_3
jumpi
tag_2:
/* "--CODEGEN--":12:13 */
0x00
/* "--CODEGEN--":9:10 */
dup1
/* "--CODEGEN--":2:14 */
revert
/* "optimizer_BlockDeDuplicator/input.sol":138:174 function f() public { true ? 1 : 3;} */
tag_3:

View File

@ -76,11 +76,8 @@ stop
sub_0: assembly {
/* "optimizer_user_yul/input.sol":60:525 contract C... */
mstore(0x40, 0x80)
/* "--CODEGEN--":12:13 */
0x00
/* "--CODEGEN--":9:10 */
dup1
/* "--CODEGEN--":2:14 */
revert
auxdata: AUXDATA REMOVED

View File

@ -1,2 +1,2 @@
{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;36:96:0;;;;;;;;;;;;;;;;12:1:-1;9;2:12;74:56:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"36:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;108:7;126:1;119:8;;74:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version!
","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}}

View File

@ -64,25 +64,6 @@ TestCase::TestResult ABIJsonTest::run(ostream& _stream, string const& _linePrefi
m_obtainedResult += jsonPrettyPrint(compiler.contractABI(contractName)) + "\n";
first = false;
}
if (m_expectation != m_obtainedResult)
{
string nextIndentLevel = _linePrefix + " ";
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Expected result:" << endl;
printIndented(_stream, m_expectation, nextIndentLevel);
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Obtained result:" << endl;
printIndented(_stream, m_obtainedResult, nextIndentLevel);
return TestResult::Failure;
}
return TestResult::Success;
}
void ABIJsonTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const
{
printIndented(_stream, m_source, _linePrefix);
}
void ABIJsonTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
{
printIndented(_stream, m_obtainedResult, _linePrefix);
return checkResult(_stream, _linePrefix, _formatted);
}

View File

@ -36,14 +36,6 @@ public:
ABIJsonTest(std::string const& _filename);
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;
void printSource(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) const override;
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
private:
std::string m_source;
std::string m_expectation;
std::string m_obtainedResult;
};
}

View File

@ -41,7 +41,6 @@ public:
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
private:
std::vector<std::pair<std::string, std::string>> m_sources;
std::string m_expectation;
std::string m_expectationLegacy;
std::string m_astFilename;
std::string m_legacyAstFilename;

View File

@ -107,13 +107,13 @@ void printAssemblyLocations(AssemblyItems const& _items)
cout <<
"\t\tvector<SourceLocation>(" <<
_repetitions <<
", SourceLocation(" <<
", SourceLocation{" <<
_loc.start <<
", " <<
_loc.end <<
", make_shared<string>(\"" <<
_loc.source->name() <<
"\"))) +" << endl;
"\")}) +" << endl;
};
vector<SourceLocation> locations;
@ -175,33 +175,13 @@ BOOST_AUTO_TEST_CASE(location_test)
vector<SourceLocation> locations;
if (solidity::test::CommonOptions::get().optimize)
locations =
vector<SourceLocation>(4, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{5, 14, codegenCharStream}) +
vector<SourceLocation>(3, SourceLocation{2, 4, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{27, 28, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{24, 25, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{17, 29, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{2, 4, codegenCharStream}) +
vector<SourceLocation>(16, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{12, 13, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{9, 10, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{2, 14, codegenCharStream}) +
vector<SourceLocation>(31, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(21, SourceLocation{20, 79, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{72, 74, sourceCode}) +
vector<SourceLocation>(2, SourceLocation{20, 79, sourceCode});
else
locations =
vector<SourceLocation>(4, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{5, 14, codegenCharStream}) +
vector<SourceLocation>(3, SourceLocation{2, 4, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{27, 28, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{24, 25, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{17, 29, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{2, 4, codegenCharStream}) +
vector<SourceLocation>(hasShifts ? 16 : 17, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{12, 13, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{9, 10, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{2, 14, codegenCharStream}) +
vector<SourceLocation>(hasShifts ? 31 : 32, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(24, SourceLocation{20, 79, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{49, 58, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{72, 74, sourceCode}) +

View File

@ -47,7 +47,6 @@ private:
bool m_optimise = false;
bool m_optimiseYul = false;
size_t m_optimiseRuns = 200;
std::string m_source;
std::map<std::string, std::map<std::string, std::string>> m_expectations;
};

View File

@ -62,6 +62,8 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer
{
m_runWithYul = false;
m_runWithoutYul = true;
// Do not try to run via yul if explicitly denied.
m_enforceViaYul = false;
}
else
BOOST_THROW_EXCEPTION(runtime_error("Invalid compileViaYul value: " + choice + "."));

View File

@ -72,14 +72,9 @@ bytes SolidityExecutionFramework::compileContract(
// get code that does not exhaust the stack.
OptimiserSettings::full()
);
if (!asmStack.parseAndAnalyze("", m_compiler.yulIROptimized(contractName)))
{
langutil::SourceReferenceFormatter formatter(std::cerr);
bool analysisSuccessful = asmStack.parseAndAnalyze("", m_compiler.yulIROptimized(contractName));
solAssert(analysisSuccessful, "Code that passed analysis in CompilerStack can't have errors");
for (auto const& error: m_compiler.errors())
formatter.printErrorInformation(*error);
BOOST_ERROR("Assembly contract failed. IR: " + m_compiler.yulIROptimized({}));
}
asmStack.optimize();
obj = std::move(*asmStack.assemble(yul::AssemblyStack::Machine::EVM).bytecode);
}

View File

@ -370,15 +370,15 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
BOOST_CHECK(contract["evm"]["assembly"].isString());
BOOST_CHECK(contract["evm"]["assembly"].asString().find(
" /* \"fileA\":0:14 contract A { } */\n mstore(0x40, 0x80)\n "
"callvalue\n /* \"--CODEGEN--\":5:14 */\n dup1\n "
"/* \"--CODEGEN--\":2:4 */\n iszero\n tag_1\n jumpi\n "
"/* \"--CODEGEN--\":27:28 */\n 0x00\n /* \"--CODEGEN--\":24:25 */\n "
"dup1\n /* \"--CODEGEN--\":17:29 */\n revert\n /* \"--CODEGEN--\":2:4 */\n"
"tag_1:\n /* \"fileA\":0:14 contract A { } */\n pop\n dataSize(sub_0)\n dup1\n "
"callvalue\n dup1\n "
"iszero\n tag_1\n jumpi\n "
"0x00\n "
"dup1\n revert\n"
"tag_1:\n pop\n dataSize(sub_0)\n dup1\n "
"dataOffset(sub_0)\n 0x00\n codecopy\n 0x00\n return\nstop\n\nsub_0: assembly {\n "
"/* \"fileA\":0:14 contract A { } */\n mstore(0x40, 0x80)\n "
"/* \"--CODEGEN--\":12:13 */\n 0x00\n /* \"--CODEGEN--\":9:10 */\n "
"dup1\n /* \"--CODEGEN--\":2:14 */\n revert\n\n auxdata: 0xa26469706673582212"
"0x00\n "
"dup1\n revert\n\n auxdata: 0xa26469706673582212"
) == 0);
BOOST_CHECK(contract["evm"]["gasEstimates"].isObject());
BOOST_CHECK_EQUAL(contract["evm"]["gasEstimates"].size(), 1);
@ -402,15 +402,15 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
"{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"source\":0,\"value\":\"40\"},"
"{\"begin\":0,\"end\":14,\"name\":\"MSTORE\",\"source\":0},"
"{\"begin\":0,\"end\":14,\"name\":\"CALLVALUE\",\"source\":0},"
"{\"begin\":5,\"end\":14,\"name\":\"DUP1\",\"source\":-1},"
"{\"begin\":2,\"end\":4,\"name\":\"ISZERO\",\"source\":-1},"
"{\"begin\":2,\"end\":4,\"name\":\"PUSH [tag]\",\"source\":-1,\"value\":\"1\"},"
"{\"begin\":2,\"end\":4,\"name\":\"JUMPI\",\"source\":-1},"
"{\"begin\":27,\"end\":28,\"name\":\"PUSH\",\"source\":-1,\"value\":\"0\"},"
"{\"begin\":24,\"end\":25,\"name\":\"DUP1\",\"source\":-1},"
"{\"begin\":17,\"end\":29,\"name\":\"REVERT\",\"source\":-1},"
"{\"begin\":2,\"end\":4,\"name\":\"tag\",\"source\":-1,\"value\":\"1\"},"
"{\"begin\":2,\"end\":4,\"name\":\"JUMPDEST\",\"source\":-1},"
"{\"begin\":0,\"end\":14,\"name\":\"DUP1\",\"source\":0},"
"{\"begin\":0,\"end\":14,\"name\":\"ISZERO\",\"source\":0},"
"{\"begin\":0,\"end\":14,\"name\":\"PUSH [tag]\",\"source\":0,\"value\":\"1\"},"
"{\"begin\":0,\"end\":14,\"name\":\"JUMPI\",\"source\":0},"
"{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"source\":0,\"value\":\"0\"},"
"{\"begin\":0,\"end\":14,\"name\":\"DUP1\",\"source\":0},"
"{\"begin\":0,\"end\":14,\"name\":\"REVERT\",\"source\":0},"
"{\"begin\":0,\"end\":14,\"name\":\"tag\",\"source\":0,\"value\":\"1\"},"
"{\"begin\":0,\"end\":14,\"name\":\"JUMPDEST\",\"source\":0},"
"{\"begin\":0,\"end\":14,\"name\":\"POP\",\"source\":0},"
"{\"begin\":0,\"end\":14,\"name\":\"PUSH #[$]\",\"source\":0,\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
"{\"begin\":0,\"end\":14,\"name\":\"DUP1\",\"source\":0},"

View File

@ -0,0 +1,27 @@
pragma experimental SMTChecker;
contract C {
struct S {
int[] b;
}
S s;
struct T {
S s;
}
T t;
function f() public {
s.b.push();
t.s.b.push();
}
}
// ----
// Warning: (72-75): Assertion checker does not yet support the type of this variable.
// Warning: (100-103): Assertion checker does not yet support the type of this variable.
// Warning: (130-133): Assertion checker does not yet support this expression.
// Warning: (130-131): Assertion checker does not yet implement type struct C.S storage ref
// Warning: (130-133): Assertion checker does not yet implement this expression.
// Warning: (144-149): Assertion checker does not yet support this expression.
// Warning: (144-147): Assertion checker does not yet implement type struct C.S storage ref
// Warning: (144-147): Assertion checker does not yet support this expression.
// Warning: (144-145): Assertion checker does not yet implement type struct C.T storage ref
// Warning: (144-149): Assertion checker does not yet implement this expression.

View File

@ -0,0 +1,33 @@
pragma experimental SMTChecker;
contract C {
struct S {
int[] b;
}
S s;
struct T {
S[] s;
}
T t;
function f() public {
s.b.push();
t.s.push();
t.s[0].b.push();
}
}
// ----
// Warning: (72-75): Assertion checker does not yet support the type of this variable.
// Warning: (102-105): Assertion checker does not yet support the type of this variable.
// Warning: (132-135): Assertion checker does not yet support this expression.
// Warning: (132-133): Assertion checker does not yet implement type struct C.S storage ref
// Warning: (132-135): Assertion checker does not yet implement this expression.
// Warning: (146-149): Assertion checker does not yet support this expression.
// Warning: (146-147): Assertion checker does not yet implement type struct C.T storage ref
// Warning: (146-156): Assertion checker does not yet implement type struct C.S storage ref
// Warning: (146-149): Assertion checker does not yet implement this expression.
// Warning: (160-168): Assertion checker does not yet support this expression.
// Warning: (160-163): Assertion checker does not yet support this expression.
// Warning: (160-161): Assertion checker does not yet implement type struct C.T storage ref
// Warning: (160-166): Assertion checker does not yet implement type struct C.S storage ref
// Warning: (160-166): Assertion checker does not yet implement this expression.
// Warning: (160-168): Assertion checker does not yet implement this expression.

View File

@ -0,0 +1,12 @@
pragma experimental SMTChecker;
contract C {
function g() public returns (uint) {
try this.g() returns (uint x) { x; }
catch Error(string memory s) { s; }
}
}
// ====
// EVMVersion: >=byzantium
// ----
// Warning: (98-121): Assertion checker does not support try/catch clauses.
// Warning: (124-159): Assertion checker does not support try/catch clauses.

View File

@ -0,0 +1,14 @@
pragma experimental SMTChecker;
contract C {
function f() public {
try this.f() {}
catch (bytes memory x) {
x;
}
}
}
// ====
// EVMVersion: >=byzantium
// ----
// Warning: (83-85): Assertion checker does not support try/catch clauses.
// Warning: (88-122): Assertion checker does not support try/catch clauses.

View File

@ -0,0 +1,5 @@
pragma experimental SMTChecker;
contract c {
bool b = (f() == 0) && (f() == 0);
function f() internal returns (uint) {}
}

View File

@ -0,0 +1,12 @@
pragma experimental SMTChecker;
contract c {
uint x;
function f() internal returns (uint) {
x = x + 1;
}
bool b = (f() > 0) || (f() > 0);
}
// ----
// Warning: (100-105): Overflow (resulting value larger than 2**256 - 1) happens here
// Warning: (100-105): Underflow (resulting value less than 0) happens here
// Warning: (100-105): Overflow (resulting value larger than 2**256 - 1) happens here

View File

@ -0,0 +1,18 @@
pragma experimental SMTChecker;
contract C {
function f() public pure {
int8 x = 1;
int8 y = 0;
assert(x & y != 0);
x = -1; y = 3;
assert(x & y == 3);
y = -1;
int8 z = x & y;
assert(z == -1);
y = 127;
assert(x & y == 127);
}
}
// ----
// Warning: (104-122): Assertion violation happens here

View File

@ -0,0 +1,12 @@
pragma experimental SMTChecker;
contract C {
function f() public pure {
assert(1 & 0 != 0);
assert(-1 & 3 == 3);
assert(-1 & -1 == -1);
assert(-1 & 127 == 127);
}
}
// ----
// Warning: (76-94): Assertion violation happens here

View File

@ -0,0 +1,18 @@
pragma experimental SMTChecker;
contract C {
function f() public pure {
uint8 x = 1;
uint16 y = 0;
assert(x & y != 0);
x = 0xff;
y = 0xffff;
assert(x & y == 0xff);
assert(x & y == 0xffff);
assert(x & y == 0x0000);
}
}
// ----
// Warning: (107-125): Assertion violation happens here
// Warning: (180-203): Assertion violation happens here
// Warning: (207-230): Assertion violation happens here

View File

@ -0,0 +1,42 @@
pragma experimental SMTChecker;
contract C {
uint[] a;
uint[][] b;
function f(uint x, uint y, uint v) public {
a[x] = v;
delete a;
assert(a[y] == 0);
}
function g(uint x, uint y, uint v) public {
b[x][y] = v;
delete b;
assert(b[y][x] == 0);
}
function h(uint x, uint y, uint v) public {
b[x][y] = v;
delete b[x];
// Not necessarily the case.
assert(b[y][x] == 0);
}
function i(uint x, uint y, uint v) public {
b[x][y] = v;
delete b[y];
assert(b[y][x] == 0);
}
function j(uint x, uint y, uint z, uint v) public {
b[x][y] = v;
delete b[z];
// Not necessarily the case.
assert(b[y][x] == 0);
}
function setA(uint x, uint y) public {
a[x] = y;
}
function setB(uint x, uint y, uint z) public {
b[x][y] = z;
}
}
// ----
// Warning: (372-392): Assertion violation happens here
// Warning: (617-637): Assertion violation happens here

View File

@ -0,0 +1,19 @@
pragma experimental SMTChecker;
contract C
{
struct S {
uint x;
}
mapping (uint => S) smap;
function f(uint y, uint v) public {
if (0==1)
smap[y] = S(v);
}
}
// ----
// Warning: (140-144): Condition is always false.
// Warning: (149-156): Assertion checker does not yet implement type struct C.S storage ref
// Warning: (159-160): Assertion checker does not yet implement type type(struct C.S storage pointer)
// Warning: (159-163): Assertion checker does not yet implement type struct C.S memory
// Warning: (159-163): Assertion checker does not yet implement this expression.
// Warning: (149-163): Assertion checker does not yet implement type struct C.S storage ref

View File

@ -0,0 +1,11 @@
contract A {
function f() virtual internal {}
}
contract B is A {
function f() virtual override internal {}
function h() pure internal { f; }
}
contract C is B {
function f() override internal {}
function i() pure internal { f; }
}

View File

@ -0,0 +1,8 @@
contract C {
function f() public pure {
assembly {
pop(add(add(1, 2), c))
}
}
int constant c = 1;
}

View File

@ -0,0 +1,12 @@
contract C {
function f() {
assembly {
c := add(add(1, 2), c)
}
}
int constant c = 0 + 1;
}
// ----
// SyntaxError: (15-83): No visibility specified. Did you intend to add "public"?
// TypeError: (71-72): Constant variables with non-literal values cannot be forward referenced from inline assembly.
// TypeError: (51-52): Constant variables cannot be assigned to.

View File

@ -81,7 +81,7 @@ bytes BytesUtils::convertBoolean(string const& _literal)
else if (_literal == "false")
return bytes{false};
else
throw Error(Error::Type::ParserError, "Boolean literal invalid.");
throw TestParserError("Boolean literal invalid.");
}
bytes BytesUtils::convertNumber(string const& _literal)
@ -92,7 +92,7 @@ bytes BytesUtils::convertNumber(string const& _literal)
}
catch (std::exception const&)
{
throw Error(Error::Type::ParserError, "Number encoding invalid.");
throw TestParserError("Number encoding invalid.");
}
}
@ -104,7 +104,7 @@ bytes BytesUtils::convertHexNumber(string const& _literal)
}
catch (std::exception const&)
{
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
throw TestParserError("Hex number encoding invalid.");
}
}
@ -116,7 +116,7 @@ bytes BytesUtils::convertString(string const& _literal)
}
catch (std::exception const&)
{
throw Error(Error::Type::ParserError, "String encoding invalid.");
throw TestParserError("String encoding invalid.");
}
}

View File

@ -30,6 +30,15 @@ namespace solidity::frontend::test
while (false)
class TestParserError: virtual public util::Exception
{
public:
explicit TestParserError(std::string const& _description)
{
*this << util::errinfo_comment(_description);
}
};
/**
* Representation of a notice, warning or error that can occur while
* formatting and therefore updating an interactive function call test.

View File

@ -18,6 +18,7 @@
#include <test/libsolidity/util/TestFileParser.h>
#include <test/libsolidity/util/BytesUtils.h>
#include <test/libsolidity/util/SoltestErrors.h>
#include <test/Common.h>
#include <liblangutil/Common.h>
@ -128,9 +129,9 @@ vector<solidity::frontend::test::FunctionCall> TestFileParser::parseFunctionCall
calls.emplace_back(std::move(call));
}
catch (Error const& _e)
catch (TestParserError const& _e)
{
throw Error{_e.type(), "Line " + to_string(_lineOffset + m_lineNumber) + ": " + _e.what()};
throw TestParserError("Line " + to_string(_lineOffset + m_lineNumber) + ": " + _e.what());
}
}
}
@ -150,8 +151,7 @@ bool TestFileParser::accept(soltest::Token _token, bool const _expect)
bool TestFileParser::expect(soltest::Token _token, bool const _advance)
{
if (m_scanner.currentToken() != _token || m_scanner.currentToken() == Token::Invalid)
throw Error(
Error::Type::ParserError,
throw TestParserError(
"Unexpected " + formatToken(m_scanner.currentToken()) + ": \"" +
m_scanner.currentLiteral() + "\". " +
"Expected \"" + formatToken(_token) + "\"."
@ -187,10 +187,10 @@ pair<string, bool> TestFileParser::parseFunctionSignature()
parameters += parseIdentifierOrTuple();
}
if (accept(Token::Arrow, true))
throw Error(Error::Type::ParserError, "Invalid signature detected: " + signature);
throw TestParserError("Invalid signature detected: " + signature);
if (!hasName && !parameters.empty())
throw Error(Error::Type::ParserError, "Signatures without a name cannot have parameters: " + signature);
throw TestParserError("Signatures without a name cannot have parameters: " + signature);
else
signature += parameters;
@ -207,7 +207,7 @@ FunctionValue TestFileParser::parseFunctionCallValue()
u256 value{ parseDecimalNumber() };
Token token = m_scanner.currentToken();
if (token != Token::Ether && token != Token::Wei)
throw Error(Error::Type::ParserError, "Invalid value unit provided. Coins can be wei or ether.");
throw TestParserError("Invalid value unit provided. Coins can be wei or ether.");
m_scanner.scanNextToken();
@ -216,7 +216,7 @@ FunctionValue TestFileParser::parseFunctionCallValue()
}
catch (std::exception const&)
{
throw Error(Error::Type::ParserError, "Ether value encoding invalid.");
throw TestParserError("Ether value encoding invalid.");
}
}
@ -226,7 +226,7 @@ FunctionCallArgs TestFileParser::parseFunctionCallArguments()
auto param = parseParameter();
if (param.abiType.type == ABIType::None)
throw Error(Error::Type::ParserError, "No argument provided.");
throw TestParserError("No argument provided.");
arguments.parameters.emplace_back(param);
while (accept(Token::Comma, true))
@ -290,7 +290,7 @@ Parameter TestFileParser::parseParameter()
if (accept(Token::Boolean))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid boolean literal.");
throw TestParserError("Invalid boolean literal.");
parameter.abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32};
string parsed = parseBoolean();
@ -304,7 +304,7 @@ Parameter TestFileParser::parseParameter()
else if (accept(Token::HexNumber))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid hex number literal.");
throw TestParserError("Invalid hex number literal.");
parameter.abiType = ABIType{ABIType::Hex, ABIType::AlignRight, 32};
string parsed = parseHexNumber();
@ -318,9 +318,9 @@ Parameter TestFileParser::parseParameter()
else if (accept(Token::Hex, true))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid hex string literal.");
throw TestParserError("Invalid hex string literal.");
if (parameter.alignment != Parameter::Alignment::None)
throw Error(Error::Type::ParserError, "Hex string literals cannot be aligned or padded.");
throw TestParserError("Hex string literals cannot be aligned or padded.");
string parsed = parseString();
parameter.rawString += "hex\"" + parsed + "\"";
@ -332,9 +332,9 @@ Parameter TestFileParser::parseParameter()
else if (accept(Token::String))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid string literal.");
throw TestParserError("Invalid string literal.");
if (parameter.alignment != Parameter::Alignment::None)
throw Error(Error::Type::ParserError, "String literals cannot be aligned or padded.");
throw TestParserError("String literals cannot be aligned or padded.");
string parsed = parseString();
parameter.abiType = ABIType{ABIType::String, ABIType::AlignLeft, parsed.size()};
@ -364,7 +364,7 @@ Parameter TestFileParser::parseParameter()
else if (accept(Token::Failure, true))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid failure literal.");
throw TestParserError("Invalid failure literal.");
parameter.abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0};
parameter.rawBytes = bytes{};
@ -555,10 +555,7 @@ void TestFileParser::Scanner::scanNextToken()
else if (isEndOfLine())
token = make_pair(Token::EOS, "EOS");
else
throw Error(
Error::Type::ParserError,
"Unexpected character: '" + string{current()} + "'"
);
throw TestParserError("Unexpected character: '" + string{current()} + "'");
break;
}
}
@ -651,7 +648,7 @@ string TestFileParser::Scanner::scanString()
str += scanHexPart();
break;
default:
throw Error(Error::Type::ParserError, "Invalid or escape sequence found in string literal.");
throw TestParserError("Invalid or escape sequence found in string literal.");
}
}
else
@ -673,7 +670,7 @@ char TestFileParser::Scanner::scanHexPart()
else if (tolower(current()) >= 'a' && tolower(current()) <= 'f')
value = tolower(current()) - 'a' + 10;
else
throw Error(Error::Type::ParserError, "\\x used with no following hex digits.");
throw TestParserError("\\x used with no following hex digits.");
advance();
if (current() == '"')

View File

@ -25,6 +25,7 @@
#include <liblangutil/Exceptions.h>
#include <test/ExecutionFramework.h>
#include <test/libsolidity/util/SoltestErrors.h>
#include <test/libsolidity/util/TestFileParser.h>
using namespace std;
@ -365,7 +366,7 @@ BOOST_AUTO_TEST_CASE(scanner_hex_values_invalid1)
char const* source = R"(
// f(uint256): "\x" ->
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(scanner_hex_values_invalid2)
@ -383,7 +384,7 @@ BOOST_AUTO_TEST_CASE(scanner_hex_values_invalid3)
char const* source = R"(
// f(uint256): "\xZ" ->
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(scanner_hex_values_invalid4)
@ -391,7 +392,7 @@ BOOST_AUTO_TEST_CASE(scanner_hex_values_invalid4)
char const* source = R"(
// f(uint256): "\xZZ" ->
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arguments_hex_string)
@ -741,7 +742,7 @@ BOOST_AUTO_TEST_CASE(call_arguments_hex_string_left_align)
char const* source = R"(
// f(bytes): left(hex"4200ef") ->
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arguments_hex_string_right_align)
@ -749,7 +750,7 @@ BOOST_AUTO_TEST_CASE(call_arguments_hex_string_right_align)
char const* source = R"(
// f(bytes): right(hex"4200ef") ->
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_newline_invalid)
@ -757,7 +758,7 @@ BOOST_AUTO_TEST_CASE(call_newline_invalid)
char const* source = R"(
/
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_invalid)
@ -765,7 +766,7 @@ BOOST_AUTO_TEST_CASE(call_invalid)
char const* source = R"(
/ f() ->
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_signature_invalid)
@ -773,7 +774,7 @@ BOOST_AUTO_TEST_CASE(call_signature_invalid)
char const* source = R"(
// f(uint8,) -> FAILURE
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arguments_tuple_invalid)
@ -781,7 +782,7 @@ BOOST_AUTO_TEST_CASE(call_arguments_tuple_invalid)
char const* source = R"(
// f((uint8,) -> FAILURE
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arguments_tuple_invalid_empty)
@ -789,7 +790,7 @@ BOOST_AUTO_TEST_CASE(call_arguments_tuple_invalid_empty)
char const* source = R"(
// f(uint8, ()) -> FAILURE
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arguments_tuple_invalid_parantheses)
@ -797,14 +798,14 @@ BOOST_AUTO_TEST_CASE(call_arguments_tuple_invalid_parantheses)
char const* source = R"(
// f((uint8,() -> FAILURE
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_ether_value_expectations_missing)
{
char const* source = R"(
// f(), 0)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arguments_invalid)
@ -812,7 +813,7 @@ BOOST_AUTO_TEST_CASE(call_arguments_invalid)
char const* source = R"(
// f(uint256): abc -> 1
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arguments_invalid_decimal)
@ -820,7 +821,7 @@ BOOST_AUTO_TEST_CASE(call_arguments_invalid_decimal)
char const* source = R"(
// sig(): 0.h3 ->
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_ether_value_invalid)
@ -828,7 +829,7 @@ BOOST_AUTO_TEST_CASE(call_ether_value_invalid)
char const* source = R"(
// f(uint256), abc : 1 -> 1
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_ether_value_invalid_decimal)
@ -836,7 +837,7 @@ BOOST_AUTO_TEST_CASE(call_ether_value_invalid_decimal)
char const* source = R"(
// sig(): 0.1hd ether ->
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_ether_type_invalid)
@ -844,7 +845,7 @@ BOOST_AUTO_TEST_CASE(call_ether_type_invalid)
char const* source = R"(
// f(uint256), 2 btc : 1 -> 1
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_signed_bool_invalid)
@ -852,7 +853,7 @@ BOOST_AUTO_TEST_CASE(call_signed_bool_invalid)
char const* source = R"(
// f() -> -true
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_signed_failure_invalid)
@ -860,7 +861,7 @@ BOOST_AUTO_TEST_CASE(call_signed_failure_invalid)
char const* source = R"(
// f() -> -FAILURE
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_signed_hex_number_invalid)
@ -868,7 +869,7 @@ BOOST_AUTO_TEST_CASE(call_signed_hex_number_invalid)
char const* source = R"(
// f() -> -0x42
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arguments_colon)
@ -877,7 +878,7 @@ BOOST_AUTO_TEST_CASE(call_arguments_colon)
// h256():
// -> 1
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arguments_newline_colon)
@ -887,7 +888,7 @@ BOOST_AUTO_TEST_CASE(call_arguments_newline_colon)
// :
// -> 1
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_arrow_missing)
@ -895,7 +896,7 @@ BOOST_AUTO_TEST_CASE(call_arrow_missing)
char const* source = R"(
// h256() FAILURE
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(call_unexpected_character)
@ -903,7 +904,7 @@ BOOST_AUTO_TEST_CASE(call_unexpected_character)
char const* source = R"(
// f() -> ??
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
BOOST_REQUIRE_THROW(parse(source), TestParserError);
}
BOOST_AUTO_TEST_CASE(constructor)

View File

@ -36,10 +36,10 @@ BOOST_AUTO_TEST_CASE(test_small)
BOOST_CHECK_EQUAL(ipfsHashBase58({}), "QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH");
BOOST_CHECK_EQUAL(ipfsHashBase58("x"), "QmULKig5Fxrs2sC4qt9nNduucXfb92AFYQ6Hi3YRqDmrYC");
BOOST_CHECK_EQUAL(ipfsHashBase58("Solidity\n"), "QmSsm9M7PQRBnyiz1smizk8hZw3URfk8fSeHzeTo3oZidS");
BOOST_CHECK_EQUAL(ipfsHashBase58(string(size_t(200), char(0))), "QmSXR1N23uWzsANi8wpxMPw5dmmhqBVUAb4hUrHVLpNaMr");
BOOST_CHECK_EQUAL(ipfsHashBase58(string(size_t(10250), char(0))), "QmVJJBB3gKKBWYC9QTywpH8ZL1bDeTDJ17B63Af5kino9i");
BOOST_CHECK_EQUAL(ipfsHashBase58(string(size_t(100000), char(0))), "QmYgKa25YqEGpQmmZtPPFMNK3kpqqneHk6nMSEUYryEX1C");
BOOST_CHECK_EQUAL(ipfsHashBase58(string(size_t(121071), char(0))), "QmdMdRshQmqvyc92N82r7AKYdUF5FRh4DJo6GtrmEk3wgj");
BOOST_CHECK_EQUAL(ipfsHashBase58(string(200ul, char(0))), "QmSXR1N23uWzsANi8wpxMPw5dmmhqBVUAb4hUrHVLpNaMr");
BOOST_CHECK_EQUAL(ipfsHashBase58(string(10250ul, char(0))), "QmVJJBB3gKKBWYC9QTywpH8ZL1bDeTDJ17B63Af5kino9i");
BOOST_CHECK_EQUAL(ipfsHashBase58(string(100000ul, char(0))), "QmYgKa25YqEGpQmmZtPPFMNK3kpqqneHk6nMSEUYryEX1C");
BOOST_CHECK_EQUAL(ipfsHashBase58(string(121071ul, char(0))), "QmdMdRshQmqvyc92N82r7AKYdUF5FRh4DJo6GtrmEk3wgj");
}
BOOST_AUTO_TEST_CASE(test_medium)

View File

@ -71,27 +71,7 @@ TestCase::TestResult EwasmTranslationTest::run(ostream& _stream, string const& _
m_obtainedResult = interpret();
if (m_expectation != m_obtainedResult)
{
string nextIndentLevel = _linePrefix + " ";
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Expected result:" << endl;
// TODO could compute a simple diff with highlighted lines
printIndented(_stream, m_expectation, nextIndentLevel);
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Obtained result:" << endl;
printIndented(_stream, m_obtainedResult, nextIndentLevel);
return TestResult::Failure;
}
return TestResult::Success;
}
void EwasmTranslationTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const
{
printIndented(_stream, m_source, _linePrefix);
}
void EwasmTranslationTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
{
printIndented(_stream, m_obtainedResult, _linePrefix);
return checkResult(_stream, _linePrefix, _formatted);
}
bool EwasmTranslationTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted)

View File

@ -42,20 +42,13 @@ public:
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;
void printSource(std::ostream& _stream, std::string const &_linePrefix = "", bool const _formatted = false) const override;
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
private:
bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted);
std::string interpret();
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
std::string m_source;
std::string m_expectation;
std::shared_ptr<Object> m_object;
std::string m_obtainedResult;
};
}

View File

@ -87,37 +87,5 @@ TestCase::TestResult FunctionSideEffects::run(ostream& _stream, string const& _l
for (auto const& fun: functionSideEffectsStr)
m_obtainedResult += fun.first + ":" + (fun.second.empty() ? "" : " ") + fun.second + "\n";
if (m_expectation != m_obtainedResult)
{
string nextIndentLevel = _linePrefix + " ";
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Expected result:" << endl;
printIndented(_stream, m_expectation, nextIndentLevel);
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Obtained result:" << endl;
printIndented(_stream, m_obtainedResult, nextIndentLevel);
return TestResult::Failure;
}
return TestResult::Success;
}
void FunctionSideEffects::printSource(ostream& _stream, string const& _linePrefix, bool const) const
{
printIndented(_stream, m_source, _linePrefix);
}
void FunctionSideEffects::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
{
printIndented(_stream, m_obtainedResult, _linePrefix);
}
void FunctionSideEffects::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const
{
stringstream output(_output);
string line;
while (getline(output, line))
if (line.empty())
// Avoid trailing spaces.
_stream << boost::trim_right_copy(_linePrefix) << endl;
else
_stream << _linePrefix << line << endl;
return checkResult(_stream, _linePrefix, _formatted);
}

View File

@ -36,16 +36,6 @@ public:
explicit FunctionSideEffects(std::string const& _filename);
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;
void printSource(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) const override;
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
private:
void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const;
std::string m_source;
std::string m_expectation;
std::string m_obtainedResult;
};
}

View File

@ -78,38 +78,7 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li
(obj.sourceMappings->empty() ? "" : " " + *obj.sourceMappings) +
"\n";
if (m_expectation != m_obtainedResult)
{
string nextIndentLevel = _linePrefix + " ";
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Expected result:" << endl;
printIndented(_stream, m_expectation, nextIndentLevel);
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Obtained result:" << endl;
printIndented(_stream, m_obtainedResult, nextIndentLevel);
return TestResult::Failure;
}
return TestResult::Success;
}
void ObjectCompilerTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const
{
printIndented(_stream, m_source, _linePrefix);
}
void ObjectCompilerTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
{
printIndented(_stream, m_obtainedResult, _linePrefix);
}
void ObjectCompilerTest::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const
{
stringstream output(_output);
string line;
while (getline(output, line))
if (line.empty())
// Avoid trailing spaces.
_stream << boost::trim_right_copy(_linePrefix) << endl;
else
_stream << _linePrefix << line << endl;
return checkResult(_stream, _linePrefix, _formatted);
}
void ObjectCompilerTest::printErrors(ostream& _stream, ErrorList const& _errors)

View File

@ -47,20 +47,13 @@ public:
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;
void printSource(std::ostream& _stream, std::string const &_linePrefix = "", bool const _formatted = false) const override;
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
private:
void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const;
bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted);
void disambiguate();
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
std::string m_source;
bool m_optimize = false;
std::string m_expectation;
std::string m_obtainedResult;
};
}

View File

@ -59,27 +59,7 @@ TestCase::TestResult YulInterpreterTest::run(ostream& _stream, string const& _li
m_obtainedResult = interpret();
if (m_expectation != m_obtainedResult)
{
string nextIndentLevel = _linePrefix + " ";
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Expected result:" << endl;
// TODO could compute a simple diff with highlighted lines
printIndented(_stream, m_expectation, nextIndentLevel);
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Obtained result:" << endl;
printIndented(_stream, m_obtainedResult, nextIndentLevel);
return TestResult::Failure;
}
return TestResult::Success;
}
void YulInterpreterTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const
{
printIndented(_stream, m_source, _linePrefix);
}
void YulInterpreterTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
{
printIndented(_stream, m_obtainedResult, _linePrefix);
return checkResult(_stream, _linePrefix, _formatted);
}
bool YulInterpreterTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted)

View File

@ -47,21 +47,14 @@ public:
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;
void printSource(std::ostream& _stream, std::string const &_linePrefix = "", bool const _formatted = false) const override;
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
private:
bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted);
std::string interpret();
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
std::string m_source;
std::string m_expectation;
std::shared_ptr<Block> m_ast;
std::shared_ptr<AsmAnalysisInfo> m_analysisInfo;
std::string m_obtainedResult;
};
}

View File

@ -354,27 +354,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
m_obtainedResult = "step: " + m_optimizerStep + "\n\n" + AsmPrinter{ *m_dialect }(*m_ast) + "\n";
if (m_expectation != m_obtainedResult)
{
string nextIndentLevel = _linePrefix + " ";
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Expected result:" << endl;
// TODO could compute a simple diff with highlighted lines
printIndented(_stream, m_expectation, nextIndentLevel);
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Obtained result:" << endl;
printIndented(_stream, m_obtainedResult, nextIndentLevel);
return TestResult::Failure;
}
return TestResult::Success;
}
void YulOptimizerTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const
{
printIndented(_stream, m_source, _linePrefix);
}
void YulOptimizerTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const
{
printIndented(_stream, m_obtainedResult, _linePrefix);
return checkResult(_stream, _linePrefix, _formatted);
}
bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted)

View File

@ -56,9 +56,6 @@ public:
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;
void printSource(std::ostream& _stream, std::string const &_linePrefix = "", bool const _formatted = false) const override;
void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override;
private:
bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted);
void disambiguate();
@ -66,9 +63,7 @@ private:
static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors);
std::string m_source;
std::string m_optimizerStep;
std::string m_expectation;
Dialect const* m_dialect = nullptr;
std::set<YulString> m_reservedIdentifiers;
@ -77,7 +72,6 @@ private:
std::shared_ptr<Block> m_ast;
std::shared_ptr<AsmAnalysisInfo> m_analysisInfo;
std::string m_obtainedResult;
};
}

View File

@ -156,7 +156,7 @@ void FuzzerUtil::testConstantOptimizer(string const& _input, bool _quiet)
assembly.append(n);
}
for (bool isCreation: {false, true})
for (unsigned runs: {1, 2, 3, 20, 40, 100, 200, 400, 1000})
for (unsigned runs: {1u, 2u, 3u, 20u, 40u, 100u, 200u, 400u, 1000u})
{
// Make a copy here so that each time we start with the original state.
Assembly tmp = assembly;

View File

@ -48,10 +48,10 @@ u256 readZeroExtended(bytes const& _data, u256 const& _offset)
if (_offset >= _data.size())
return 0;
else if (_offset + 32 <= _data.size())
return *reinterpret_cast<h256 const*>(_data.data() + size_t(_offset));
return *reinterpret_cast<h256 const*>(_data.data() + static_cast<size_t>(_offset));
else
{
size_t off = size_t(_offset);
size_t off = static_cast<size_t>(_offset);
u256 val;
for (size_t i = 0; i < 32; ++i)
{
@ -88,7 +88,7 @@ u256 EVMInstructionInterpreter::eval(
using evmasm::Instruction;
auto info = instructionInfo(_instruction);
yulAssert(size_t(info.args) == _arguments.size(), "");
yulAssert(static_cast<size_t>(info.args) == _arguments.size(), "");
auto const& arg = _arguments;
switch (_instruction)
@ -442,7 +442,7 @@ u256 EVMInstructionInterpreter::evalBuiltin(BuiltinFunctionForEVM const& _fun, c
m_state.memory,
m_state.code,
size_t(_arguments.at(0)),
size_t(_arguments.at(1) & size_t(-1)),
size_t(_arguments.at(1) & numeric_limits<size_t>::max()),
size_t(_arguments.at(2))
);
}

View File

@ -87,9 +87,9 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
copyZeroExtended(
m_state.memory,
m_state.code,
size_t(_arguments.at(0)),
size_t(_arguments.at(1) & size_t(-1)),
size_t(_arguments.at(2))
static_cast<size_t>(_arguments.at(0)),
static_cast<size_t>(_arguments.at(1) & numeric_limits<size_t>::max()),
static_cast<size_t>(_arguments.at(2))
);
return 0;
}

View File

@ -54,7 +54,7 @@ void InterpreterState::dumpTraceAndState(ostream& _out) const
_out << "Memory dump:\n";
map<u256, u256> words;
for (auto const& [offset, value]: memory)
words[(offset / 0x20) * 0x20] |= u256(uint32_t(value)) << (256 - 8 - 8 * size_t(offset % 0x20));
words[(offset / 0x20) * 0x20] |= u256(uint32_t(value)) << (256 - 8 - 8 * static_cast<size_t>(offset % 0x20));
for (auto const& [offset, value]: words)
if (value != 0)
_out << " " << std::uppercase << std::hex << std::setw(4) << offset << ": " << h256(value).hex() << endl;

View File

@ -27,7 +27,10 @@ using namespace solidity::tools;
void UpgradeChange::apply()
{
m_source.replace(m_location.start, m_location.end - m_location.start, m_patch);
m_source.replace(
static_cast<size_t>(m_location.start),
static_cast<size_t>(m_location.end - m_location.start), m_patch
);
}
void UpgradeChange::log(bool const _shorten) const
@ -56,7 +59,7 @@ void UpgradeChange::log(bool const _shorten) const
string line;
while (getline(output, line))
{
os << string(leftpad, ' ');
os << string(static_cast<size_t>(leftpad), ' ');
AnsiColorized(os, true, {formatting::BOLD, formatting::BLUE}) << "| ";
AnsiColorized(os, true, {}) << line << endl;
}