mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into HEAD
This commit is contained in:
commit
6979952995
@ -21,8 +21,8 @@ parameters:
|
||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:2593c15689dee5b5bdfff96a36c8c68a468cd3b147c41f75b820b8fabc257be9"
|
||||
ubuntu-1604-clang-ossfuzz-docker-image:
|
||||
type: string
|
||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-4
|
||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:842126b164b3542f05bff2611459e21edc7e3e2c81ca9d1f43396c8cf066f7ca"
|
||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-5
|
||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:65901cd8b64b5959bc4c907df47bb7be3d3b00c9ae8948c75aad7d4c57875cf0"
|
||||
emscripten-docker-image:
|
||||
type: string
|
||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:23dad3b34deae8107c8551804ef299f6a89c23ed506e8118fac151e2bdc9018c"
|
||||
@ -459,6 +459,19 @@ jobs:
|
||||
FORCE_RELEASE: ON
|
||||
MAKEFLAGS: -j 10
|
||||
|
||||
b_ubu_static:
|
||||
<<: *build_ubuntu2004
|
||||
environment:
|
||||
MAKEFLAGS: -j 10
|
||||
CMAKE_OPTIONS: -DCMAKE_BUILD_TYPE=Release -DSOLC_LINK_STATIC=1 -DUSE_CVC4=OFF -DUSE_Z3=OFF
|
||||
steps:
|
||||
- checkout
|
||||
- run: *run_build
|
||||
- run:
|
||||
name: strip binary
|
||||
command: strip build/solc/solc
|
||||
- store_artifacts: *artifacts_solc
|
||||
|
||||
b_ubu18: &build_ubuntu1804
|
||||
docker:
|
||||
- image: << pipeline.parameters.ubuntu-1804-docker-image >>
|
||||
@ -910,7 +923,8 @@ jobs:
|
||||
keys:
|
||||
- dependencies-win-{{ checksum "scripts/install_deps.ps1" }}
|
||||
# DO NOT EDIT between here and save_cache, but rather edit .\scripts\install_deps.ps1
|
||||
# WARNING! If you do edit anything here instead, remember to invalidate the cache manually. - run:
|
||||
# WARNING! If you do edit anything here instead, remember to invalidate the cache manually.
|
||||
- run:
|
||||
name: "Installing dependencies"
|
||||
command: .\scripts\install_deps.ps1
|
||||
- save_cache:
|
||||
@ -949,6 +963,7 @@ jobs:
|
||||
- run:
|
||||
name: "Run soltest"
|
||||
command: .circleci/soltest.ps1
|
||||
- store_test_results: *store_test_results
|
||||
- store_artifacts: *artifacts_test_results
|
||||
|
||||
t_win_release:
|
||||
@ -1059,6 +1074,9 @@ workflows:
|
||||
- b_archlinux: *workflow_trigger_on_tags
|
||||
- t_archlinux_soltest: *workflow_archlinux
|
||||
|
||||
# Static build
|
||||
- b_ubu_static: *workflow_trigger_on_tags
|
||||
|
||||
# Ubuntu build and tests
|
||||
- b_ubu: *workflow_trigger_on_tags
|
||||
- b_ubu18: *workflow_trigger_on_tags
|
||||
|
@ -236,7 +236,7 @@ Example:
|
||||
#include <numeric>
|
||||
```
|
||||
|
||||
See [this issue](http://stackoverflow.com/questions/614302/c-header-order/614333#614333 "C header order") for the reason: this makes it easier to find missing includes in header files.
|
||||
See [this issue](https://stackoverflow.com/questions/614302/c-header-order/614333#614333 "C header order") for the reason: this makes it easier to find missing includes in header files.
|
||||
|
||||
## 13. Recommended reading
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Contribution Guidelines
|
||||
|
||||
Please see our contribution guidelines in [the Solidity documentation](http://solidity.readthedocs.io/en/latest/contributing.html).
|
||||
Please see our contribution guidelines in [the Solidity documentation](https://solidity.readthedocs.io/en/latest/contributing.html).
|
||||
|
||||
Thank you for your help!
|
||||
|
22
Changelog.md
22
Changelog.md
@ -19,7 +19,12 @@ Language Features:
|
||||
AST Changes:
|
||||
* New node type: unchecked block - used for ``unchecked { ... }``.
|
||||
|
||||
### 0.7.4 (unreleased)
|
||||
|
||||
### 0.7.5 (unreleased)
|
||||
|
||||
|
||||
|
||||
### 0.7.4 (2020-10-19)
|
||||
|
||||
Important Bugfixes:
|
||||
* Code Generator: Fix data corruption bug when copying empty byte arrays from memory or calldata to storage.
|
||||
@ -30,19 +35,24 @@ Language Features:
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Command Line Interface: New option ``--model-checker-engine`` allows to choose a specific SMTChecker engine. Options are ``all`` (default), ``bmc``, ``chc`` and ``none``.
|
||||
* Control Flow Graph: Print warning for non-empty functions with unnamed return parameters that are not assigned a value in all code paths.
|
||||
* SMTChecker: Support ``keccak256``, ``sha256``, ``ripemd160`` and ``ecrecover`` in the CHC engine.
|
||||
* SMTChecker: Support inline arrays.
|
||||
* SMTChecker: Support variables ``block``, ``msg`` and ``tx`` in the CHC engine.
|
||||
* Control Flow Graph: Print warning for non-empty functions with unnamed return parameters that are not assigned a value in all code paths.
|
||||
* Standard JSON: New option ``modelCheckerSettings.engine`` allows to choose a specific SMTChecker engine. Options are ``all`` (default), ``bmc``, ``chc`` and ``none``.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* Code generator: Fix internal error on returning structs containing mappings from library function.
|
||||
* Code generator: Fix internal compiler error when referencing members via module name but not using the reference.
|
||||
* Code generator: Fix ``ABIEncoderV2`` pragma from the current module affecting inherited functions and applied modifiers.
|
||||
* Code generator: Fix internal compiler error when referencing members via module name but not using the reference.
|
||||
* Code generator: Fix internal error on returning structs containing mappings from library function.
|
||||
* Code generator: Use revert instead of invalid opcode for out-of-bounds array index access in getter.
|
||||
* Type Checker: Fix internal compiler error caused by storage parameters with nested mappings in libraries.
|
||||
* Name Resolver: Fix shadowing/same-name warnings for later declarations.
|
||||
* Contract Level Checker: Add missing check against inheriting functions with ABIEncoderV2 return types in ABIEncoderV1 contracts.
|
||||
* Name Resolver: Fix shadowing/same-name warnings for later declarations.
|
||||
* Type Checker: Allow arrays of contract types as type expressions and as arguments for ``abi.decode``.
|
||||
* Type Checker: Disallow invalid use of library names as type name.
|
||||
* Type Checker: Fix internal compiler error caused by storage parameters with nested mappings in libraries.
|
||||
|
||||
|
||||
### 0.7.3 (2020-10-07)
|
||||
|
@ -1365,5 +1365,9 @@
|
||||
"EmptyByteArrayCopy"
|
||||
],
|
||||
"released": "2020-10-07"
|
||||
},
|
||||
"0.7.4": {
|
||||
"bugs": [],
|
||||
"released": "2020-10-19"
|
||||
}
|
||||
}
|
@ -341,7 +341,12 @@ Input Description
|
||||
"def": {
|
||||
"MyContract": [ "abi", "evm.bytecode.opcodes" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"modelCheckerSettings":
|
||||
{
|
||||
// Choose which model checker engine to use: all (default), bmc, chc, none.
|
||||
"engine": "chc"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ void SourceReferenceFormatterHuman::printExceptionInformation(SourceReferenceExt
|
||||
for (auto const& secondary: _msg.secondary)
|
||||
{
|
||||
secondaryColored() << "Note";
|
||||
messageColored() << ": " << secondary.message << '\n';
|
||||
messageColored() << ":" << (secondary.message.empty() ? "" : (" " + secondary.message)) << '\n';
|
||||
printSourceLocation(secondary);
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,11 @@ void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName)
|
||||
else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
|
||||
_typeName.annotation().type = TypeProvider::enumType(*enumDef);
|
||||
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
||||
{
|
||||
if (contract->isLibrary())
|
||||
m_errorReporter.typeError(1130_error, _typeName.location(), "Invalid use of a library name.");
|
||||
_typeName.annotation().type = TypeProvider::contract(*contract);
|
||||
}
|
||||
else
|
||||
{
|
||||
_typeName.annotation().type = TypeProvider::emptyTuple();
|
||||
@ -201,23 +205,19 @@ void DeclarationTypeChecker::endVisit(Mapping const& _mapping)
|
||||
return;
|
||||
|
||||
if (auto const* typeName = dynamic_cast<UserDefinedTypeName const*>(&_mapping.keyType()))
|
||||
{
|
||||
if (auto const* contractType = dynamic_cast<ContractType const*>(typeName->annotation().type))
|
||||
switch (typeName->annotation().type->category())
|
||||
{
|
||||
if (contractType->contractDefinition().isLibrary())
|
||||
case Type::Category::Enum:
|
||||
case Type::Category::Contract:
|
||||
break;
|
||||
default:
|
||||
m_errorReporter.fatalTypeError(
|
||||
1665_error,
|
||||
7804_error,
|
||||
typeName->location(),
|
||||
"Library types cannot be used as mapping keys."
|
||||
"Only elementary types, contract types or enums are allowed as mapping keys."
|
||||
);
|
||||
break;
|
||||
}
|
||||
else if (typeName->annotation().type->category() != Type::Category::Enum)
|
||||
m_errorReporter.fatalTypeError(
|
||||
7804_error,
|
||||
typeName->location(),
|
||||
"Only elementary types, contract types or enums are allowed as mapping keys."
|
||||
);
|
||||
}
|
||||
else
|
||||
solAssert(dynamic_cast<ElementaryTypeName const*>(&_mapping.keyType()), "");
|
||||
|
||||
@ -243,6 +243,7 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
|
||||
solAssert(!m_errorReporter.errors().empty(), "");
|
||||
return;
|
||||
}
|
||||
|
||||
solAssert(baseType->storageBytes() != 0, "Illegal base type of storage size zero for array.");
|
||||
if (Expression const* length = _typeName.length())
|
||||
{
|
||||
@ -392,13 +393,36 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
||||
_variable.annotation().type = type;
|
||||
}
|
||||
|
||||
void DeclarationTypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
bool DeclarationTypeChecker::visit(UsingForDirective const& _usingFor)
|
||||
{
|
||||
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
|
||||
_usingFor.libraryName().annotation().referencedDeclaration
|
||||
);
|
||||
|
||||
if (!library || !library->isLibrary())
|
||||
m_errorReporter.fatalTypeError(4357_error, _usingFor.libraryName().location(), "Library name expected.");
|
||||
|
||||
_usingFor.libraryName().annotation().type = TypeProvider::contract(*library);
|
||||
if (_usingFor.typeName())
|
||||
_usingFor.typeName()->accept(*this);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeclarationTypeChecker::visit(InheritanceSpecifier const& _inheritanceSpecifier)
|
||||
{
|
||||
auto const* contract = dynamic_cast<ContractDefinition const*>(_inheritanceSpecifier.name().annotation().referencedDeclaration);
|
||||
solAssert(contract, "");
|
||||
if (contract->isLibrary())
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
2571_error,
|
||||
_inheritanceSpecifier.name().location(),
|
||||
"Libraries cannot be inherited from."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeclarationTypeChecker::check(ASTNode const& _node)
|
||||
|
@ -59,7 +59,8 @@ private:
|
||||
void endVisit(ArrayTypeName const& _typeName) override;
|
||||
void endVisit(VariableDeclaration const& _variable) override;
|
||||
bool visit(StructDefinition const& _struct) override;
|
||||
void endVisit(UsingForDirective const& _usingForDirective) override;
|
||||
bool visit(UsingForDirective const& _usingForDirective) override;
|
||||
bool visit(InheritanceSpecifier const& _inheritanceSpecifier) override;
|
||||
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
|
@ -276,9 +276,6 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
||||
if (m_currentContract->isInterface() && !base->isInterface())
|
||||
m_errorReporter.typeError(6536_error, _inheritance.location(), "Interfaces can only inherit from other interfaces.");
|
||||
|
||||
if (base->isLibrary())
|
||||
m_errorReporter.typeError(2571_error, _inheritance.location(), "Libraries cannot be inherited from.");
|
||||
|
||||
auto const& arguments = _inheritance.arguments();
|
||||
TypePointers parameterTypes;
|
||||
if (!base->isInterface())
|
||||
@ -511,9 +508,6 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
TypePointer varType = _variable.annotation().type;
|
||||
solAssert(!!varType, "Variable type not provided.");
|
||||
|
||||
if (auto contractType = dynamic_cast<ContractType const*>(varType))
|
||||
if (contractType->contractDefinition().isLibrary())
|
||||
m_errorReporter.typeError(1273_error, _variable.location(), "The type of a variable cannot be a library.");
|
||||
if (_variable.value())
|
||||
{
|
||||
if (_variable.isStateVariable() && varType->containsNestedMapping())
|
||||
@ -2924,8 +2918,9 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
case Type::Category::TypeType:
|
||||
{
|
||||
TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType);
|
||||
if (dynamic_cast<ContractType const*>(typeType.actualType()))
|
||||
m_errorReporter.typeError(2876_error, _access.location(), "Index access for contracts or libraries is not possible.");
|
||||
if (auto const* contractType = dynamic_cast<ContractType const*>(typeType.actualType()))
|
||||
if (contractType->contractDefinition().isLibrary())
|
||||
m_errorReporter.typeError(2876_error, _access.location(), "Index access for library types and arrays of libraries are not possible.");
|
||||
if (!index)
|
||||
resultType = TypeProvider::typeType(TypeProvider::array(DataLocation::Memory, typeType.actualType()));
|
||||
else
|
||||
|
@ -1052,9 +1052,11 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
|
||||
{
|
||||
solAssert(_type.location() == DataLocation::Storage, "");
|
||||
solAssert(_type.isDynamicallySized(), "");
|
||||
solUnimplementedAssert(!_type.isByteArray(), "Byte Arrays not yet implemented!");
|
||||
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "...");
|
||||
|
||||
if (_type.isByteArray())
|
||||
return resizeDynamicByteArrayFunction(_type);
|
||||
|
||||
string functionName = "resize_array_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
@ -1099,6 +1101,151 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::resizeDynamicByteArrayFunction(ArrayType const& _type)
|
||||
{
|
||||
string functionName = "resize_array_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(array, newLen) {
|
||||
if gt(newLen, <maxArrayLength>) {
|
||||
<panic>()
|
||||
}
|
||||
|
||||
let data := sload(array)
|
||||
let oldLen := <extractLength>(data)
|
||||
|
||||
if gt(newLen, oldLen) {
|
||||
<increaseSize>(array, data, oldLen, newLen)
|
||||
}
|
||||
|
||||
if lt(newLen, oldLen) {
|
||||
<decreaseSize>(array, data, oldLen, newLen)
|
||||
}
|
||||
})")
|
||||
("functionName", functionName)
|
||||
("panic", panicFunction())
|
||||
("extractLength", extractByteArrayLengthFunction())
|
||||
("maxArrayLength", (u256(1) << 64).str())
|
||||
("decreaseSize", decreaseByteArraySizeFunction(_type))
|
||||
("increaseSize", increaseByteArraySizeFunction(_type))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::decreaseByteArraySizeFunction(ArrayType const& _type)
|
||||
{
|
||||
string functionName = "byte_array_decrease_size_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(array, data, oldLen, newLen) {
|
||||
switch lt(newLen, 32)
|
||||
case 0 {
|
||||
let arrayDataStart := <dataPosition>(array)
|
||||
let deleteStart := add(arrayDataStart, div(add(newLen, 31), 32))
|
||||
|
||||
// we have to partially clear last slot that is still used
|
||||
let offset := and(newLen, 0x1f)
|
||||
if offset { <partialClearStorageSlot>(sub(deleteStart, 1), offset) }
|
||||
|
||||
<clearStorageRange>(deleteStart, add(arrayDataStart, div(add(oldLen, 31), 32)))
|
||||
|
||||
sstore(array, or(mul(2, newLen), 1))
|
||||
}
|
||||
default {
|
||||
switch gt(oldLen, 31)
|
||||
case 1 {
|
||||
let arrayDataStart := <dataPosition>(array)
|
||||
// clear whole old array, as we are transforming to short bytes array
|
||||
<clearStorageRange>(add(arrayDataStart, 1), add(arrayDataStart, div(add(oldLen, 31), 32)))
|
||||
<transitLongToShort>(array, newLen)
|
||||
}
|
||||
default {
|
||||
sstore(array, <encodeUsedSetLen>(data, newLen))
|
||||
}
|
||||
}
|
||||
})")
|
||||
("functionName", functionName)
|
||||
("dataPosition", arrayDataAreaFunction(_type))
|
||||
("partialClearStorageSlot", partialClearStorageSlotFunction())
|
||||
("clearStorageRange", clearStorageRangeFunction(*_type.baseType()))
|
||||
("transitLongToShort", byteArrayTransitLongToShortFunction(_type))
|
||||
("encodeUsedSetLen", shortByteArrayEncodeUsedAreaSetLengthFunction())
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::increaseByteArraySizeFunction(ArrayType const& _type)
|
||||
{
|
||||
string functionName = "byte_array_increase_size_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(array, data, oldLen, newLen) {
|
||||
switch lt(oldLen, 32)
|
||||
case 0 {
|
||||
// in this case array stays unpacked, so we just set new length
|
||||
sstore(array, add(mul(2, newLen), 1))
|
||||
}
|
||||
default {
|
||||
switch lt(newLen, 32)
|
||||
case 0 {
|
||||
// we need to copy elements to data area as we changed array from packed to unpacked
|
||||
data := and(not(0xff), data)
|
||||
sstore(<dataPosition>(array), data)
|
||||
sstore(array, add(mul(2, newLen), 1))
|
||||
}
|
||||
default {
|
||||
// here array stays packed, we just need to increase length
|
||||
sstore(array, <encodeUsedSetLen>(data, newLen))
|
||||
}
|
||||
}
|
||||
})")
|
||||
("functionName", functionName)
|
||||
("dataPosition", arrayDataAreaFunction(_type))
|
||||
("encodeUsedSetLen", shortByteArrayEncodeUsedAreaSetLengthFunction())
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::byteArrayTransitLongToShortFunction(ArrayType const& _type)
|
||||
{
|
||||
string functionName = "transit_byte_array_long_to_short_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(array, len) {
|
||||
// we need to copy elements from old array to new
|
||||
// we want to copy only elements that are part of the array after resizing
|
||||
let dataPos := <dataPosition>(array)
|
||||
let data := <extractUsedApplyLen>(sload(dataPos), len)
|
||||
sstore(array, data)
|
||||
sstore(dataPos, 0)
|
||||
})")
|
||||
("functionName", functionName)
|
||||
("dataPosition", arrayDataAreaFunction(_type))
|
||||
("extractUsedApplyLen", shortByteArrayEncodeUsedAreaSetLengthFunction())
|
||||
("shl", shiftLeftFunctionDynamic())
|
||||
("ones", formatNumber((bigint(1) << 256) - 1))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::shortByteArrayEncodeUsedAreaSetLengthFunction()
|
||||
{
|
||||
string functionName = "extract_used_part_and_set_length_of_short_byte_array";
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(data, len) -> used {
|
||||
// we want to save only elements that are part of the array after resizing
|
||||
// others should be set to zero
|
||||
let mask := <shl>(mul(8, sub(32, len)), <ones>)
|
||||
used := or(and(data, mask), mul(2, len))
|
||||
})")
|
||||
("functionName", functionName)
|
||||
("shl", shiftLeftFunctionDynamic())
|
||||
("ones", formatNumber((bigint(1) << 256) - 1))
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::storageArrayPopFunction(ArrayType const& _type)
|
||||
{
|
||||
solAssert(_type.location() == DataLocation::Storage, "");
|
||||
@ -1141,36 +1288,30 @@ string YulUtilFunctions::storageByteArrayPopFunction(ArrayType const& _type)
|
||||
let oldLen := <extractByteArrayLength>(data)
|
||||
if iszero(oldLen) { <panic>() }
|
||||
|
||||
switch eq(oldLen, 32)
|
||||
case 1 {
|
||||
switch oldLen
|
||||
case 32 {
|
||||
// Here we have a special case where array transitions to shorter than 32
|
||||
// So we need to copy data
|
||||
let copyFromSlot := <dataAreaFunction>(array)
|
||||
data := sload(copyFromSlot)
|
||||
sstore(copyFromSlot, 0)
|
||||
// New length is 31, encoded to 31 * 2 = 62
|
||||
data := or(and(data, not(0xff)), 62)
|
||||
<transitLongToShort>(array, 31)
|
||||
}
|
||||
default {
|
||||
data := sub(data, 2)
|
||||
let newLen := sub(oldLen, 1)
|
||||
switch lt(oldLen, 32)
|
||||
case 1 {
|
||||
// set last element to zero
|
||||
let mask := not(<shl>(mul(8, sub(31, newLen)), 0xff))
|
||||
data := and(data, mask)
|
||||
sstore(array, <encodeUsedSetLen>(data, newLen))
|
||||
}
|
||||
default {
|
||||
let slot, offset := <indexAccess>(array, newLen)
|
||||
<setToZero>(slot, offset)
|
||||
sstore(array, sub(data, 2))
|
||||
}
|
||||
}
|
||||
sstore(array, data)
|
||||
})")
|
||||
("functionName", functionName)
|
||||
("panic", panicFunction())
|
||||
("extractByteArrayLength", extractByteArrayLengthFunction())
|
||||
("dataAreaFunction", arrayDataAreaFunction(_type))
|
||||
("transitLongToShort", byteArrayTransitLongToShortFunction(_type))
|
||||
("encodeUsedSetLen", shortByteArrayEncodeUsedAreaSetLengthFunction())
|
||||
("indexAccess", storageArrayIndexAccessFunction(_type))
|
||||
("setToZero", storageSetToZeroFunction(*_type.baseType()))
|
||||
("shl", shiftLeftFunctionDynamic())
|
||||
@ -2075,7 +2216,10 @@ string YulUtilFunctions::updateStorageValueFunction(
|
||||
fromReferenceType->location(),
|
||||
fromReferenceType->isPointer()
|
||||
).get() == *fromReferenceType, "");
|
||||
solUnimplementedAssert(fromReferenceType->location() != DataLocation::Storage, "");
|
||||
solUnimplementedAssert(
|
||||
fromReferenceType->location() != DataLocation::Storage,
|
||||
"Copying from storage to storage is not yet implemented."
|
||||
);
|
||||
solAssert(toReferenceType->category() == fromReferenceType->category(), "");
|
||||
|
||||
if (_toType.category() == Type::Category::Array)
|
||||
|
@ -464,6 +464,29 @@ private:
|
||||
/// signature: (slot) ->
|
||||
std::string clearStorageStructFunction(StructType const& _type);
|
||||
|
||||
/// @returns the name of a function that resizes a storage byte array
|
||||
/// signature: (array, newLen)
|
||||
std::string resizeDynamicByteArrayFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that increases size of byte array
|
||||
/// when we resize byte array frextractUsedSetLenom < 32 elements to >= 32 elements or we push to byte array of size 31 copying of data will occur
|
||||
/// signature: (array, data, oldLen, newLen)
|
||||
std::string increaseByteArraySizeFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that decreases size of byte array
|
||||
/// when we resize byte array from >= 32 elements to < 32 elements or we pop from byte array of size 32 copying of data will occur
|
||||
/// signature: (array, data, oldLen, newLen)
|
||||
std::string decreaseByteArraySizeFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that sets size of short byte array while copying data
|
||||
/// should be called when we resize from long byte array (more than 32 elements) to short byte array
|
||||
/// signature: (array, data, len)
|
||||
std::string byteArrayTransitLongToShortFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that extracts only used part of slot that represents short byte array
|
||||
/// signature: (data, len) -> data
|
||||
std::string shortByteArrayEncodeUsedAreaSetLengthFunction();
|
||||
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
RevertStrings m_revertStrings;
|
||||
MultiUseYulFunctionCollector& m_functionCollector;
|
||||
|
@ -668,6 +668,9 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
|
||||
string IRGenerator::memoryInit(bool _useMemoryGuard)
|
||||
{
|
||||
// TODO: Remove once we have made sure it is safe, i.e. after "Yul memory objects lite".
|
||||
// Also restore the tests removed in the commit that adds this comment.
|
||||
_useMemoryGuard = false;
|
||||
// This function should be called at the beginning of the EVM call frame
|
||||
// and thus can assume all memory to be zero, including the contents of
|
||||
// the "zero memory area" (the position CompilerUtils::zeroPointer points to).
|
||||
|
@ -385,13 +385,6 @@ void BMC::endVisit(FunctionCall const& _funCall)
|
||||
SMTEncoder::endVisit(_funCall);
|
||||
internalOrExternalFunctionCall(_funCall);
|
||||
break;
|
||||
case FunctionType::Kind::KECCAK256:
|
||||
case FunctionType::Kind::ECRecover:
|
||||
case FunctionType::Kind::SHA256:
|
||||
case FunctionType::Kind::RIPEMD160:
|
||||
SMTEncoder::endVisit(_funCall);
|
||||
abstractFunctionCall(_funCall);
|
||||
break;
|
||||
case FunctionType::Kind::Send:
|
||||
case FunctionType::Kind::Transfer:
|
||||
{
|
||||
@ -408,6 +401,10 @@ void BMC::endVisit(FunctionCall const& _funCall)
|
||||
SMTEncoder::endVisit(_funCall);
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::KECCAK256:
|
||||
case FunctionType::Kind::ECRecover:
|
||||
case FunctionType::Kind::SHA256:
|
||||
case FunctionType::Kind::RIPEMD160:
|
||||
case FunctionType::Kind::BlockHash:
|
||||
case FunctionType::Kind::AddMod:
|
||||
case FunctionType::Kind::MulMod:
|
||||
@ -485,16 +482,6 @@ void BMC::inlineFunctionCall(FunctionCall const& _funCall)
|
||||
createReturnedExpressions(_funCall);
|
||||
}
|
||||
|
||||
void BMC::abstractFunctionCall(FunctionCall const& _funCall)
|
||||
{
|
||||
vector<smtutil::Expression> smtArguments;
|
||||
for (auto const& arg: _funCall.arguments())
|
||||
smtArguments.push_back(expr(*arg));
|
||||
defineExpr(_funCall, (*m_context.expression(_funCall.expression()))(smtArguments));
|
||||
m_uninterpretedTerms.insert(&_funCall);
|
||||
setSymbolicUnknownValue(expr(_funCall), _funCall.annotation().type, m_context);
|
||||
}
|
||||
|
||||
void BMC::internalOrExternalFunctionCall(FunctionCall const& _funCall)
|
||||
{
|
||||
auto const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
|
||||
@ -836,7 +823,7 @@ void BMC::checkCondition(
|
||||
"\nNote that some information is erased after the execution of loops.\n"
|
||||
"You can re-introduce information using require().";
|
||||
if (m_externalFunctionCallHappened)
|
||||
extraComment+=
|
||||
extraComment +=
|
||||
"\nNote that external function calls are not inlined,"
|
||||
" even if the source code of the function is available."
|
||||
" This is due to the possibility that the actual called contract"
|
||||
@ -854,7 +841,7 @@ void BMC::checkCondition(
|
||||
if (_callStack.size())
|
||||
{
|
||||
std::ostringstream modelMessage;
|
||||
modelMessage << "\nCounterexample:\n";
|
||||
modelMessage << "Counterexample:\n";
|
||||
solAssert(values.size() == expressionNames.size(), "");
|
||||
map<string, string> sortedModel;
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
@ -863,6 +850,7 @@ void BMC::checkCondition(
|
||||
|
||||
for (auto const& eval: sortedModel)
|
||||
modelMessage << " " << eval.first << " = " << eval.second << "\n";
|
||||
|
||||
m_errorReporter.warning(
|
||||
_errorHappens,
|
||||
_location,
|
||||
|
@ -99,8 +99,6 @@ private:
|
||||
/// Visits the FunctionDefinition of the called function
|
||||
/// if available and inlines the return value.
|
||||
void inlineFunctionCall(FunctionCall const& _funCall);
|
||||
/// Creates an uninterpreted function call.
|
||||
void abstractFunctionCall(FunctionCall const& _funCall);
|
||||
/// Inlines if the function call is internal or external to `this`.
|
||||
/// Erases knowledge about state variables if external.
|
||||
void internalOrExternalFunctionCall(FunctionCall const& _funCall);
|
||||
|
@ -120,7 +120,7 @@ void CHC::endVisit(ContractDefinition const& _contract)
|
||||
&_contract
|
||||
);
|
||||
addRule(
|
||||
(*implicitConstructorPredicate)({0, state().thisAddress(), state().tx(), state().state()}),
|
||||
(*implicitConstructorPredicate)({0, state().thisAddress(), state().crypto(), state().tx(), state().state()}),
|
||||
implicitConstructorPredicate->functor().name
|
||||
);
|
||||
setCurrentBlock(*implicitConstructorPredicate);
|
||||
@ -874,7 +874,7 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source)
|
||||
auto nondetPre = smt::nondetInterface(iface, *contract, m_context, 0, 1);
|
||||
auto nondetPost = smt::nondetInterface(iface, *contract, m_context, 0, 2);
|
||||
|
||||
vector<smtutil::Expression> args{errorFlag().currentValue(), state().thisAddress(), state().tx(), state().state(1)};
|
||||
vector<smtutil::Expression> args{errorFlag().currentValue(), state().thisAddress(), state().crypto(), state().tx(), state().state(1)};
|
||||
args += state1 +
|
||||
applyMap(function->parameters(), [this](auto _var) { return valueAtIndex(*_var, 0); }) +
|
||||
vector<smtutil::Expression>{state().state(2)} +
|
||||
@ -1053,7 +1053,7 @@ smtutil::Expression CHC::predicate(FunctionCall const& _funCall)
|
||||
return smtutil::Expression(true);
|
||||
|
||||
errorFlag().increaseIndex();
|
||||
vector<smtutil::Expression> args{errorFlag().currentValue(), state().thisAddress(), state().tx(), state().state()};
|
||||
vector<smtutil::Expression> args{errorFlag().currentValue(), state().thisAddress(), state().crypto(), state().tx(), state().state()};
|
||||
|
||||
FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
|
||||
solAssert(funType.kind() == FunctionType::Kind::Internal, "");
|
||||
@ -1298,7 +1298,7 @@ void CHC::checkAndReportTarget(
|
||||
_errorReporterId,
|
||||
_scope->location(),
|
||||
"CHC: " + _satMsg,
|
||||
SecondarySourceLocation().append("\nCounterexample:\n" + *cex, SourceLocation{})
|
||||
SecondarySourceLocation().append("Counterexample:\n" + *cex, SourceLocation{})
|
||||
);
|
||||
else
|
||||
m_outerErrorReporter.warning(
|
||||
@ -1402,9 +1402,13 @@ optional<string> CHC::generateCounterexample(CHCSolverInterface::CexGraph const&
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto modelMsg = formatVariableModel(*stateVars, stateValues, ", ");
|
||||
/// We report the state after every tx in the trace except for the last, which is reported
|
||||
/// first in the code above.
|
||||
path.emplace_back("State: " + formatVariableModel(*stateVars, stateValues, ", "));
|
||||
if (!modelMsg.empty())
|
||||
path.emplace_back("State: " + modelMsg);
|
||||
}
|
||||
|
||||
string txCex = summaryPredicate->formatSummaryCall(summaryArgs);
|
||||
path.emplace_back(txCex);
|
||||
|
@ -27,9 +27,11 @@ using namespace solidity::frontend;
|
||||
ModelChecker::ModelChecker(
|
||||
ErrorReporter& _errorReporter,
|
||||
map<h256, string> const& _smtlib2Responses,
|
||||
ModelCheckerEngine _engine,
|
||||
ReadCallback::Callback const& _smtCallback,
|
||||
smtutil::SMTSolverChoice _enabledSolvers
|
||||
):
|
||||
m_engine(_engine),
|
||||
m_context(),
|
||||
m_bmc(m_context, _errorReporter, _smtlib2Responses, _smtCallback, _enabledSolvers),
|
||||
m_chc(m_context, _errorReporter, _smtlib2Responses, _smtCallback, _enabledSolvers)
|
||||
@ -41,13 +43,15 @@ void ModelChecker::analyze(SourceUnit const& _source)
|
||||
if (!_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
|
||||
return;
|
||||
|
||||
m_chc.analyze(_source);
|
||||
if (m_engine.chc)
|
||||
m_chc.analyze(_source);
|
||||
|
||||
auto solvedTargets = m_chc.safeTargets();
|
||||
for (auto const& target: m_chc.unsafeTargets())
|
||||
solvedTargets[target.first] += target.second;
|
||||
|
||||
m_bmc.analyze(_source, solvedTargets);
|
||||
if (m_engine.bmc)
|
||||
m_bmc.analyze(_source, solvedTargets);
|
||||
}
|
||||
|
||||
vector<string> ModelChecker::unhandledQueries()
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include <libsmtutil/SolverInterface.h>
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
class ErrorReporter;
|
||||
@ -41,6 +43,34 @@ struct SourceLocation;
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
struct ModelCheckerEngine
|
||||
{
|
||||
bool bmc = false;
|
||||
bool chc = false;
|
||||
|
||||
static constexpr ModelCheckerEngine All() { return {true, true}; }
|
||||
static constexpr ModelCheckerEngine BMC() { return {true, false}; }
|
||||
static constexpr ModelCheckerEngine CHC() { return {false, true}; }
|
||||
static constexpr ModelCheckerEngine None() { return {false, false}; }
|
||||
|
||||
bool none() const { return !any(); }
|
||||
bool any() const { return bmc || chc; }
|
||||
bool all() const { return bmc && chc; }
|
||||
|
||||
static std::optional<ModelCheckerEngine> fromString(std::string const& _engine)
|
||||
{
|
||||
static std::map<std::string, ModelCheckerEngine> engineMap{
|
||||
{"all", All()},
|
||||
{"bmc", BMC()},
|
||||
{"chc", CHC()},
|
||||
{"none", None()}
|
||||
};
|
||||
if (engineMap.count(_engine))
|
||||
return engineMap.at(_engine);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
class ModelChecker
|
||||
{
|
||||
public:
|
||||
@ -49,6 +79,7 @@ public:
|
||||
ModelChecker(
|
||||
langutil::ErrorReporter& _errorReporter,
|
||||
std::map<solidity::util::h256, std::string> const& _smtlib2Responses,
|
||||
ModelCheckerEngine _engine = ModelCheckerEngine::All(),
|
||||
ReadCallback::Callback const& _smtCallback = ReadCallback::Callback(),
|
||||
smtutil::SMTSolverChoice _enabledSolvers = smtutil::SMTSolverChoice::All()
|
||||
);
|
||||
@ -64,6 +95,8 @@ public:
|
||||
static smtutil::SMTSolverChoice availableSolvers();
|
||||
|
||||
private:
|
||||
ModelCheckerEngine m_engine;
|
||||
|
||||
/// Stores the context of the encoding.
|
||||
smt::EncodingContext m_context;
|
||||
|
||||
|
@ -161,9 +161,9 @@ string Predicate::formatSummaryCall(vector<string> const& _args) const
|
||||
auto const* fun = programFunction();
|
||||
solAssert(fun, "");
|
||||
|
||||
/// The signature of a function summary predicate is: summary(error, this, txData, preBlockChainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// The signature of a function summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockChainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// Here we are interested in preInputVars.
|
||||
vector<string>::const_iterator first = _args.begin() + 4 + static_cast<int>(stateVars->size());
|
||||
vector<string>::const_iterator first = _args.begin() + 5 + static_cast<int>(stateVars->size());
|
||||
vector<string>::const_iterator last = first + static_cast<int>(fun->parameters().size());
|
||||
solAssert(first >= _args.begin() && first <= _args.end(), "");
|
||||
solAssert(last >= _args.begin() && last <= _args.end(), "");
|
||||
@ -188,10 +188,9 @@ string Predicate::formatSummaryCall(vector<string> const& _args) const
|
||||
|
||||
vector<string> Predicate::summaryStateValues(vector<string> const& _args) const
|
||||
{
|
||||
/// The signature of a function summary predicate is: summary(error, this, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// The signature of an implicit constructor summary predicate is: summary(error, this, txData, preBlockSchainState, postBlockchainState, postStateVars).
|
||||
/// The signature of a function summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// The signature of an implicit constructor summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockchainState, postBlockchainState, postStateVars).
|
||||
/// Here we are interested in postStateVars.
|
||||
|
||||
auto stateVars = stateVariables();
|
||||
solAssert(stateVars.has_value(), "");
|
||||
|
||||
@ -199,12 +198,12 @@ vector<string> Predicate::summaryStateValues(vector<string> const& _args) const
|
||||
vector<string>::const_iterator stateLast;
|
||||
if (auto const* function = programFunction())
|
||||
{
|
||||
stateFirst = _args.begin() + 4 + static_cast<int>(stateVars->size()) + static_cast<int>(function->parameters().size()) + 1;
|
||||
stateFirst = _args.begin() + 5 + static_cast<int>(stateVars->size()) + static_cast<int>(function->parameters().size()) + 1;
|
||||
stateLast = stateFirst + static_cast<int>(stateVars->size());
|
||||
}
|
||||
else if (programContract())
|
||||
{
|
||||
stateFirst = _args.begin() + 5;
|
||||
stateFirst = _args.begin() + 6;
|
||||
stateLast = stateFirst + static_cast<int>(stateVars->size());
|
||||
}
|
||||
else
|
||||
@ -220,7 +219,7 @@ vector<string> Predicate::summaryStateValues(vector<string> const& _args) const
|
||||
|
||||
vector<string> Predicate::summaryPostInputValues(vector<string> const& _args) const
|
||||
{
|
||||
/// The signature of a function summary predicate is: summary(error, this, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// The signature of a function summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// Here we are interested in postInputVars.
|
||||
auto const* function = programFunction();
|
||||
solAssert(function, "");
|
||||
@ -230,7 +229,7 @@ vector<string> Predicate::summaryPostInputValues(vector<string> const& _args) co
|
||||
|
||||
auto const& inParams = function->parameters();
|
||||
|
||||
vector<string>::const_iterator first = _args.begin() + 4 + static_cast<int>(stateVars->size()) * 2 + static_cast<int>(inParams.size()) + 1;
|
||||
vector<string>::const_iterator first = _args.begin() + 5 + static_cast<int>(stateVars->size()) * 2 + static_cast<int>(inParams.size()) + 1;
|
||||
vector<string>::const_iterator last = first + static_cast<int>(inParams.size());
|
||||
|
||||
solAssert(first >= _args.begin() && first <= _args.end(), "");
|
||||
@ -243,7 +242,7 @@ vector<string> Predicate::summaryPostInputValues(vector<string> const& _args) co
|
||||
|
||||
vector<string> Predicate::summaryPostOutputValues(vector<string> const& _args) const
|
||||
{
|
||||
/// The signature of a function summary predicate is: summary(error, this, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// The signature of a function summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// Here we are interested in outputVars.
|
||||
auto const* function = programFunction();
|
||||
solAssert(function, "");
|
||||
@ -253,7 +252,7 @@ vector<string> Predicate::summaryPostOutputValues(vector<string> const& _args) c
|
||||
|
||||
auto const& inParams = function->parameters();
|
||||
|
||||
vector<string>::const_iterator first = _args.begin() + 4 + static_cast<int>(stateVars->size()) * 2 + static_cast<int>(inParams.size()) * 2 + 1;
|
||||
vector<string>::const_iterator first = _args.begin() + 5 + static_cast<int>(stateVars->size()) * 2 + static_cast<int>(inParams.size()) * 2 + 1;
|
||||
|
||||
solAssert(first >= _args.begin() && first <= _args.end(), "");
|
||||
|
||||
|
@ -30,14 +30,14 @@ namespace solidity::frontend::smt
|
||||
smtutil::Expression interfacePre(Predicate const& _pred, ContractDefinition const& _contract, EncodingContext& _context)
|
||||
{
|
||||
auto& state = _context.state();
|
||||
vector<smtutil::Expression> stateExprs{state.thisAddress(0), state.state(0)};
|
||||
vector<smtutil::Expression> stateExprs{state.thisAddress(0), state.crypto(0), state.state(0)};
|
||||
return _pred(stateExprs + initialStateVariables(_contract, _context));
|
||||
}
|
||||
|
||||
smtutil::Expression interface(Predicate const& _pred, ContractDefinition const& _contract, EncodingContext& _context)
|
||||
{
|
||||
auto& state = _context.state();
|
||||
vector<smtutil::Expression> stateExprs{state.thisAddress(0), state.state()};
|
||||
vector<smtutil::Expression> stateExprs{state.thisAddress(0), state.crypto(0), state.state()};
|
||||
return _pred(stateExprs + currentStateVariables(_contract, _context));
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ smtutil::Expression nondetInterface(Predicate const& _pred, ContractDefinition c
|
||||
smtutil::Expression implicitConstructor(Predicate const& _pred, ContractDefinition const&, EncodingContext& _context)
|
||||
{
|
||||
auto& state = _context.state();
|
||||
vector<smtutil::Expression> stateExprs{state.errorFlag().currentValue(), state.thisAddress(0), state.tx(0), state.state(0)};
|
||||
vector<smtutil::Expression> stateExprs{state.errorFlag().currentValue(), state.thisAddress(0), state.crypto(0), state.tx(0), state.state(0)};
|
||||
return _pred(stateExprs);
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ smtutil::Expression constructor(Predicate const& _pred, ContractDefinition const
|
||||
return _pred(currentFunctionVariables(*constructor, &_contract, _context));
|
||||
|
||||
auto& state = _context.state();
|
||||
vector<smtutil::Expression> stateExprs{state.errorFlag().currentValue(), state.thisAddress(0), state.tx(0), state.state(0), state.state()};
|
||||
vector<smtutil::Expression> stateExprs{state.errorFlag().currentValue(), state.thisAddress(0), state.crypto(0), state.tx(0), state.state(0), state.state()};
|
||||
return _pred(stateExprs + currentStateVariables(_contract, _context));
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ vector<smtutil::Expression> currentFunctionVariables(
|
||||
)
|
||||
{
|
||||
auto& state = _context.state();
|
||||
vector<smtutil::Expression> exprs{_context.state().errorFlag().currentValue(), state.thisAddress(0), state.tx(0), state.state(0)};
|
||||
vector<smtutil::Expression> exprs{_context.state().errorFlag().currentValue(), state.thisAddress(0), state.crypto(0), state.tx(0), state.state(0)};
|
||||
exprs += _contract ? initialStateVariables(*_contract, _context) : vector<smtutil::Expression>{};
|
||||
exprs += applyMap(_function.parameters(), [&](auto _var) { return _context.variable(*_var)->valueAtIndex(0); });
|
||||
exprs += vector<smtutil::Expression>{state.state()};
|
||||
|
@ -31,7 +31,7 @@ namespace solidity::frontend::smt
|
||||
SortPointer interfaceSort(ContractDefinition const& _contract, SymbolicState& _state)
|
||||
{
|
||||
return make_shared<FunctionSort>(
|
||||
vector<SortPointer>{_state.thisAddressSort(), _state.stateSort()} + stateSorts(_contract),
|
||||
vector<SortPointer>{_state.thisAddressSort(), _state.cryptoSort(), _state.stateSort()} + stateSorts(_contract),
|
||||
SortProvider::boolSort
|
||||
);
|
||||
}
|
||||
@ -49,7 +49,7 @@ SortPointer nondetInterfaceSort(ContractDefinition const& _contract, SymbolicSta
|
||||
SortPointer implicitConstructorSort(SymbolicState& _state)
|
||||
{
|
||||
return make_shared<FunctionSort>(
|
||||
vector<SortPointer>{_state.errorFlagSort(), _state.thisAddressSort(), _state.txSort(), _state.stateSort()},
|
||||
vector<SortPointer>{_state.errorFlagSort(), _state.thisAddressSort(), _state.cryptoSort(), _state.txSort(), _state.stateSort()},
|
||||
SortProvider::boolSort
|
||||
);
|
||||
}
|
||||
@ -60,7 +60,7 @@ SortPointer constructorSort(ContractDefinition const& _contract, SymbolicState&
|
||||
return functionSort(*constructor, &_contract, _state);
|
||||
|
||||
return make_shared<FunctionSort>(
|
||||
vector<SortPointer>{_state.errorFlagSort(), _state.thisAddressSort(), _state.txSort(), _state.stateSort(), _state.stateSort()} + stateSorts(_contract),
|
||||
vector<SortPointer>{_state.errorFlagSort(), _state.thisAddressSort(), _state.cryptoSort(), _state.txSort(), _state.stateSort(), _state.stateSort()} + stateSorts(_contract),
|
||||
SortProvider::boolSort
|
||||
);
|
||||
}
|
||||
@ -72,7 +72,7 @@ SortPointer functionSort(FunctionDefinition const& _function, ContractDefinition
|
||||
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
||||
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
||||
return make_shared<FunctionSort>(
|
||||
vector<SortPointer>{_state.errorFlagSort(), _state.thisAddressSort(), _state.txSort(), _state.stateSort()} +
|
||||
vector<SortPointer>{_state.errorFlagSort(), _state.thisAddressSort(), _state.cryptoSort(), _state.txSort(), _state.stateSort()} +
|
||||
varSorts +
|
||||
inputSorts +
|
||||
vector<SortPointer>{_state.stateSort()} +
|
||||
|
@ -33,7 +33,7 @@ namespace solidity::frontend::smt
|
||||
*
|
||||
* 1. Interface
|
||||
* The idle state of a contract. Signature:
|
||||
* interface(this, blockchainState, stateVariables).
|
||||
* interface(this, cryptoFunctions, blockchainState, stateVariables).
|
||||
*
|
||||
* 2. Nondet interface
|
||||
* The nondeterminism behavior of a contract. Signature:
|
||||
@ -41,19 +41,19 @@ namespace solidity::frontend::smt
|
||||
*
|
||||
* 3. Implicit constructor
|
||||
* The implicit constructor of a contract, that is, without input parameters. Signature:
|
||||
* implicit_constructor(error, this, txData, blockchainState).
|
||||
* implicit_constructor(error, this, cryptoFunctions, txData, blockchainState).
|
||||
*
|
||||
* 4. Constructor entry/summary
|
||||
* The summary of an implicit constructor. Signature:
|
||||
* constructor_summary(error, this, txData, blockchainState, blockchainState', stateVariables').
|
||||
* constructor_summary(error, this, cryptoFunctions, txData, blockchainState, blockchainState', stateVariables').
|
||||
*
|
||||
* 5. Function entry/summary
|
||||
* The entry point of a function definition. Signature:
|
||||
* function_entry(error, this, txData, blockchainState, stateVariables, inputVariables, blockchainState', stateVariables', inputVariables', outputVariables').
|
||||
* function_entry(error, this, cryptoFunctions, txData, blockchainState, stateVariables, inputVariables, blockchainState', stateVariables', inputVariables', outputVariables').
|
||||
*
|
||||
* 6. Function body
|
||||
* Use for any predicate within a function. Signature:
|
||||
* function_body(error, this, txData, blockchainState, stateVariables, inputVariables, blockchainState' ,stateVariables', inputVariables', outputVariables', localVariables).
|
||||
* function_body(error, this, txData, blockchainState, stateVariables, inputVariables, blockchainState', stateVariables', inputVariables', outputVariables', localVariables).
|
||||
*/
|
||||
|
||||
/// @returns the interface predicate sort for _contract.
|
||||
|
@ -633,6 +633,7 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall)
|
||||
case FunctionType::Kind::ECRecover:
|
||||
case FunctionType::Kind::SHA256:
|
||||
case FunctionType::Kind::RIPEMD160:
|
||||
visitCryptoFunction(_funCall);
|
||||
break;
|
||||
case FunctionType::Kind::BlockHash:
|
||||
defineExpr(_funCall, m_context.state().blockhash(expr(*_funCall.arguments().at(0))));
|
||||
@ -730,6 +731,38 @@ void SMTEncoder::visitRequire(FunctionCall const& _funCall)
|
||||
addPathImpliedExpression(expr(*args.front()));
|
||||
}
|
||||
|
||||
void SMTEncoder::visitCryptoFunction(FunctionCall const& _funCall)
|
||||
{
|
||||
auto const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
|
||||
auto kind = funType.kind();
|
||||
auto arg0 = expr(*_funCall.arguments().at(0));
|
||||
optional<smtutil::Expression> result;
|
||||
if (kind == FunctionType::Kind::KECCAK256)
|
||||
result = smtutil::Expression::select(m_context.state().cryptoFunction("keccak256"), arg0);
|
||||
else if (kind == FunctionType::Kind::SHA256)
|
||||
result = smtutil::Expression::select(m_context.state().cryptoFunction("sha256"), arg0);
|
||||
else if (kind == FunctionType::Kind::RIPEMD160)
|
||||
result = smtutil::Expression::select(m_context.state().cryptoFunction("ripemd160"), arg0);
|
||||
else if (kind == FunctionType::Kind::ECRecover)
|
||||
{
|
||||
auto e = m_context.state().cryptoFunction("ecrecover");
|
||||
auto arg0 = expr(*_funCall.arguments().at(0));
|
||||
auto arg1 = expr(*_funCall.arguments().at(1));
|
||||
auto arg2 = expr(*_funCall.arguments().at(2));
|
||||
auto arg3 = expr(*_funCall.arguments().at(3));
|
||||
auto inputSort = dynamic_cast<smtutil::ArraySort&>(*e.sort).domain;
|
||||
auto ecrecoverInput = smtutil::Expression::tuple_constructor(
|
||||
smtutil::Expression(make_shared<smtutil::SortSort>(inputSort), ""),
|
||||
{arg0, arg1, arg2, arg3}
|
||||
);
|
||||
result = smtutil::Expression::select(e, ecrecoverInput);
|
||||
}
|
||||
else
|
||||
solAssert(false, "");
|
||||
|
||||
defineExpr(_funCall, *result);
|
||||
}
|
||||
|
||||
void SMTEncoder::visitGasLeft(FunctionCall const& _funCall)
|
||||
{
|
||||
string gasLeft = "gasleft()";
|
||||
@ -755,11 +788,12 @@ void SMTEncoder::visitAddMulMod(FunctionCall const& _funCall)
|
||||
auto y = expr(*args.at(1));
|
||||
auto k = expr(*args.at(2));
|
||||
m_context.addAssertion(k != 0);
|
||||
auto const& intType = dynamic_cast<IntegerType const&>(*_funCall.annotation().type);
|
||||
|
||||
if (kind == FunctionType::Kind::AddMod)
|
||||
defineExpr(_funCall, (x + y) % k);
|
||||
defineExpr(_funCall, divModWithSlacks(x + y, k, intType).second);
|
||||
else
|
||||
defineExpr(_funCall, (x * y) % k);
|
||||
defineExpr(_funCall, divModWithSlacks(x * y, k, intType).second);
|
||||
}
|
||||
|
||||
void SMTEncoder::visitObjectCreation(FunctionCall const& _funCall)
|
||||
@ -1490,8 +1524,8 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation(
|
||||
case Token::Add: return _left + _right;
|
||||
case Token::Sub: return _left - _right;
|
||||
case Token::Mul: return _left * _right;
|
||||
case Token::Div: return division(_left, _right, *intType);
|
||||
case Token::Mod: return _left % _right;
|
||||
case Token::Div: return divModWithSlacks(_left, _right, *intType).first;
|
||||
case Token::Mod: return divModWithSlacks(_left, _right, *intType).second;
|
||||
default: solAssert(false, "");
|
||||
}
|
||||
}();
|
||||
@ -1693,13 +1727,30 @@ void SMTEncoder::bitwiseNotOperation(UnaryOperation const& _op)
|
||||
defineExpr(_op, smtutil::Expression::bv2int(~bvOperand, isSigned));
|
||||
}
|
||||
|
||||
smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Expression _right, IntegerType const& _type)
|
||||
pair<smtutil::Expression, smtutil::Expression> SMTEncoder::divModWithSlacks(
|
||||
smtutil::Expression _left,
|
||||
smtutil::Expression _right,
|
||||
IntegerType const& _type
|
||||
)
|
||||
{
|
||||
// Signed division in SMTLIB2 rounds differently for negative division.
|
||||
IntegerType const* intType = &_type;
|
||||
string suffix = "div_mod_" + to_string(m_context.newUniqueId());
|
||||
smt::SymbolicIntVariable d(intType, intType, "d_" + suffix, m_context);
|
||||
smt::SymbolicIntVariable r(intType, intType, "r_" + suffix, m_context);
|
||||
|
||||
// x / y = d and x % y = r iff d * y + r = x and
|
||||
// either x >= 0 and 0 <= r < abs(y) (or just 0 <= r < y for unsigned)
|
||||
// or x < 0 and -abs(y) < r <= 0
|
||||
m_context.addAssertion(((d.currentValue() * _right) + r.currentValue()) == _left);
|
||||
if (_type.isSigned())
|
||||
return signedDivisionEVM(_left, _right);
|
||||
else
|
||||
return _left / _right;
|
||||
m_context.addAssertion(
|
||||
(_left >= 0 && 0 <= r.currentValue() && r.currentValue() < smtutil::abs(_right)) ||
|
||||
(_left < 0 && (0 - smtutil::abs(_right)) < r.currentValue() && r.currentValue() <= 0)
|
||||
);
|
||||
else // unsigned version
|
||||
m_context.addAssertion(0 <= r.currentValue() && r.currentValue() < _right);
|
||||
|
||||
return {d.currentValue(), r.currentValue()};
|
||||
}
|
||||
|
||||
void SMTEncoder::assignment(
|
||||
@ -2114,7 +2165,7 @@ SecondarySourceLocation SMTEncoder::callStackMessage(vector<CallStackEntry> cons
|
||||
{
|
||||
SecondarySourceLocation callStackLocation;
|
||||
solAssert(!_callStack.empty(), "");
|
||||
callStackLocation.append("Callstack: ", SourceLocation());
|
||||
callStackLocation.append("Callstack:", SourceLocation());
|
||||
for (auto const& call: _callStack | boost::adaptors::reversed)
|
||||
if (call.second)
|
||||
callStackLocation.append("", call.second->location());
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace solidity::langutil
|
||||
{
|
||||
@ -136,6 +137,7 @@ protected:
|
||||
void initFunction(FunctionDefinition const& _function);
|
||||
void visitAssert(FunctionCall const& _funCall);
|
||||
void visitRequire(FunctionCall const& _funCall);
|
||||
void visitCryptoFunction(FunctionCall const& _funCall);
|
||||
void visitGasLeft(FunctionCall const& _funCall);
|
||||
virtual void visitAddMulMod(FunctionCall const& _funCall);
|
||||
void visitObjectCreation(FunctionCall const& _funCall);
|
||||
@ -174,9 +176,14 @@ protected:
|
||||
std::vector<smtutil::Expression> const& _elementValues
|
||||
);
|
||||
|
||||
/// Division expression in the given type. Requires special treatment because
|
||||
/// of rounding for signed division.
|
||||
smtutil::Expression division(smtutil::Expression _left, smtutil::Expression _right, IntegerType const& _type);
|
||||
/// @returns a pair of expressions representing _left / _right and _left mod _right, respectively.
|
||||
/// Uses slack variables and additional constraints to express the results using only operations
|
||||
/// more friendly to the SMT solver (multiplication, addition, subtraction and comparison).
|
||||
std::pair<smtutil::Expression, smtutil::Expression> divModWithSlacks(
|
||||
smtutil::Expression _left,
|
||||
smtutil::Expression _right,
|
||||
IntegerType const& _type
|
||||
);
|
||||
|
||||
void assignment(VariableDeclaration const& _variable, Expression const& _value);
|
||||
/// Handles assignments to variables of different types.
|
||||
|
@ -76,6 +76,7 @@ void SymbolicState::reset()
|
||||
m_thisAddress.resetIndex();
|
||||
m_state.reset();
|
||||
m_tx.reset();
|
||||
m_crypto.reset();
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::balances() const
|
||||
|
@ -128,6 +128,16 @@ public:
|
||||
smtutil::Expression blockhash(smtutil::Expression _blockNumber) const;
|
||||
//@}
|
||||
|
||||
/// Crypto functions.
|
||||
//@{
|
||||
/// @returns the crypto functions represented as a tuple of arrays.
|
||||
smtutil::Expression crypto() const { return m_crypto.value(); }
|
||||
smtutil::Expression crypto(unsigned _idx) const { return m_crypto.value(_idx); }
|
||||
smtutil::SortPointer const& cryptoSort() const { return m_crypto.sort(); }
|
||||
void newCrypto() { m_crypto.newVar(); }
|
||||
smtutil::Expression cryptoFunction(std::string const& _member) const { return m_crypto.member(_member); }
|
||||
//@}
|
||||
|
||||
private:
|
||||
/// Adds _value to _account's balance.
|
||||
void addBalance(smtutil::Expression _account, smtutil::Expression _value);
|
||||
@ -171,6 +181,38 @@ private:
|
||||
},
|
||||
m_context
|
||||
};
|
||||
|
||||
BlockchainVariable m_crypto{
|
||||
"crypto",
|
||||
{
|
||||
{"keccak256", std::make_shared<smtutil::ArraySort>(
|
||||
smt::smtSort(*TypeProvider::bytesStorage()),
|
||||
smtSort(*TypeProvider::fixedBytes(32))
|
||||
)},
|
||||
{"sha256", std::make_shared<smtutil::ArraySort>(
|
||||
smt::smtSort(*TypeProvider::bytesStorage()),
|
||||
smtSort(*TypeProvider::fixedBytes(32))
|
||||
)},
|
||||
{"ripemd160", std::make_shared<smtutil::ArraySort>(
|
||||
smt::smtSort(*TypeProvider::bytesStorage()),
|
||||
smtSort(*TypeProvider::fixedBytes(20))
|
||||
)},
|
||||
{"ecrecover", std::make_shared<smtutil::ArraySort>(
|
||||
std::make_shared<smtutil::TupleSort>(
|
||||
"ecrecover_input_type",
|
||||
std::vector<std::string>{"hash", "v", "r", "s"},
|
||||
std::vector<smtutil::SortPointer>{
|
||||
smt::smtSort(*TypeProvider::fixedBytes(32)),
|
||||
smt::smtSort(*TypeProvider::uint(8)),
|
||||
smt::smtSort(*TypeProvider::fixedBytes(32)),
|
||||
smt::smtSort(*TypeProvider::fixedBytes(32))
|
||||
}
|
||||
),
|
||||
smtSort(*TypeProvider::address())
|
||||
)}
|
||||
},
|
||||
m_context
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ static int g_compilerStackCounts = 0;
|
||||
|
||||
CompilerStack::CompilerStack(ReadCallback::Callback _readFile):
|
||||
m_readFile{std::move(_readFile)},
|
||||
m_modelCheckerEngine{ModelCheckerEngine::All()},
|
||||
m_enabledSMTSolvers{smtutil::SMTSolverChoice::All()},
|
||||
m_errorReporter{m_errorList}
|
||||
{
|
||||
@ -138,6 +139,13 @@ void CompilerStack::setEVMVersion(langutil::EVMVersion _version)
|
||||
m_evmVersion = _version;
|
||||
}
|
||||
|
||||
void CompilerStack::setModelCheckerEngine(ModelCheckerEngine _engine)
|
||||
{
|
||||
if (m_stackState >= ParsedAndImported)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set enabled model checking engines before parsing."));
|
||||
m_modelCheckerEngine = _engine;
|
||||
}
|
||||
|
||||
void CompilerStack::setSMTSolverChoice(smtutil::SMTSolverChoice _enabledSMTSolvers)
|
||||
{
|
||||
if (m_stackState >= ParsedAndImported)
|
||||
@ -207,6 +215,7 @@ void CompilerStack::reset(bool _keepSettings)
|
||||
m_remappings.clear();
|
||||
m_libraries.clear();
|
||||
m_evmVersion = langutil::EVMVersion();
|
||||
m_modelCheckerEngine = ModelCheckerEngine::All();
|
||||
m_enabledSMTSolvers = smtutil::SMTSolverChoice::All();
|
||||
m_generateIR = false;
|
||||
m_generateEwasm = false;
|
||||
@ -443,7 +452,7 @@ bool CompilerStack::analyze()
|
||||
|
||||
if (noErrors)
|
||||
{
|
||||
ModelChecker modelChecker(m_errorReporter, m_smtlib2Responses, m_readFile, m_enabledSMTSolvers);
|
||||
ModelChecker modelChecker(m_errorReporter, m_smtlib2Responses, m_modelCheckerEngine, m_readFile, m_enabledSMTSolvers);
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast)
|
||||
modelChecker.analyze(*source->ast);
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libsolidity/interface/DebugSettings.h>
|
||||
|
||||
#include <libsolidity/formal/ModelChecker.h>
|
||||
|
||||
#include <libsmtutil/SolverInterface.h>
|
||||
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
@ -165,6 +167,8 @@ public:
|
||||
/// Must be set before parsing.
|
||||
void setEVMVersion(langutil::EVMVersion _version = langutil::EVMVersion{});
|
||||
|
||||
/// Set which model checking engines should be used.
|
||||
void setModelCheckerEngine(ModelCheckerEngine _engine);
|
||||
/// Set which SMT solvers should be enabled.
|
||||
void setSMTSolverChoice(smtutil::SMTSolverChoice _enabledSolvers);
|
||||
|
||||
@ -452,6 +456,7 @@ private:
|
||||
RevertStrings m_revertStrings = RevertStrings::Default;
|
||||
State m_stopAfter = State::CompilationSuccessful;
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
ModelCheckerEngine m_modelCheckerEngine;
|
||||
smtutil::SMTSolverChoice m_enabledSMTSolvers;
|
||||
std::map<std::string, std::set<std::string>> m_requestedContractNames;
|
||||
bool m_generateEvmBytecode = true;
|
||||
|
@ -396,7 +396,7 @@ std::optional<Json::Value> checkKeys(Json::Value const& _input, set<string> cons
|
||||
|
||||
std::optional<Json::Value> checkRootKeys(Json::Value const& _input)
|
||||
{
|
||||
static set<string> keys{"auxiliaryInput", "language", "settings", "sources"};
|
||||
static set<string> keys{"auxiliaryInput", "language", "modelCheckerSettings", "settings", "sources"};
|
||||
return checkKeys(_input, keys, "root");
|
||||
}
|
||||
|
||||
@ -418,6 +418,12 @@ std::optional<Json::Value> checkSettingsKeys(Json::Value const& _input)
|
||||
return checkKeys(_input, keys, "settings");
|
||||
}
|
||||
|
||||
std::optional<Json::Value> checkModelCheckerSettingsKeys(Json::Value const& _input)
|
||||
{
|
||||
static set<string> keys{"engine"};
|
||||
return checkKeys(_input, keys, "modelCheckerSettings");
|
||||
}
|
||||
|
||||
std::optional<Json::Value> checkOptimizerKeys(Json::Value const& _input)
|
||||
{
|
||||
static set<string> keys{"details", "enabled", "runs"};
|
||||
@ -527,6 +533,7 @@ std::optional<Json::Value> checkOutputSelection(Json::Value const& _outputSelect
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Validates the optimizer settings and returns them in a parsed object.
|
||||
/// On error returns the json-formatted error message.
|
||||
std::variant<OptimiserSettings, Json::Value> parseOptimizerSettings(Json::Value const& _jsonInput)
|
||||
@ -866,6 +873,21 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
|
||||
"Requested output selection conflicts with \"settings.stopAfter\"."
|
||||
);
|
||||
|
||||
Json::Value const& modelCheckerSettings = _input.get("modelCheckerSettings", Json::Value());
|
||||
|
||||
if (auto result = checkModelCheckerSettingsKeys(modelCheckerSettings))
|
||||
return *result;
|
||||
|
||||
if (modelCheckerSettings.isMember("engine"))
|
||||
{
|
||||
if (!modelCheckerSettings["engine"].isString())
|
||||
return formatFatalError("JSONError", "modelCheckerSettings.engine must be a string.");
|
||||
std::optional<ModelCheckerEngine> engine = ModelCheckerEngine::fromString(modelCheckerSettings["engine"].asString());
|
||||
if (!engine)
|
||||
return formatFatalError("JSONError", "Invalid model checker engine requested.");
|
||||
ret.modelCheckerEngine = *engine;
|
||||
}
|
||||
|
||||
return { std::move(ret) };
|
||||
}
|
||||
|
||||
@ -886,6 +908,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
compilerStack.useMetadataLiteralSources(_inputsAndSettings.metadataLiteralSources);
|
||||
compilerStack.setMetadataHash(_inputsAndSettings.metadataHash);
|
||||
compilerStack.setRequestedContractNames(requestedContractNames(_inputsAndSettings.outputSelection));
|
||||
compilerStack.setModelCheckerEngine(_inputsAndSettings.modelCheckerEngine);
|
||||
|
||||
compilerStack.enableEvmBytecodeGeneration(isEvmBytecodeRequested(_inputsAndSettings.outputSelection));
|
||||
compilerStack.enableIRGeneration(isIRRequested(_inputsAndSettings.outputSelection));
|
||||
|
@ -71,6 +71,7 @@ private:
|
||||
bool metadataLiteralSources = false;
|
||||
CompilerStack::MetadataHash metadataHash = CompilerStack::MetadataHash::IPFS;
|
||||
Json::Value outputSelection;
|
||||
ModelCheckerEngine modelCheckerEngine = ModelCheckerEngine::All();
|
||||
};
|
||||
|
||||
/// Parses the input json (and potentially invokes the read callback) and either returns
|
||||
|
@ -22,7 +22,7 @@
|
||||
# (c) 2016-2019 solidity contributors.
|
||||
#------------------------------------------------------------------------------
|
||||
FROM gcr.io/oss-fuzz-base/base-clang as base
|
||||
LABEL version="4"
|
||||
LABEL version="5"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
@ -32,7 +32,7 @@ RUN apt-get update; \
|
||||
software-properties-common \
|
||||
ninja-build git wget \
|
||||
libbz2-dev zlib1g-dev git curl uuid-dev \
|
||||
pkg-config openjdk-8-jdk liblzma-dev unzip; \
|
||||
pkg-config openjdk-8-jdk liblzma-dev unzip mlton; \
|
||||
apt-get install -qy python-pip python-sphinx;
|
||||
|
||||
# Install cmake 3.14 (minimum requirement is cmake 3.10)
|
||||
@ -43,20 +43,24 @@ RUN wget https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5
|
||||
FROM base AS libraries
|
||||
|
||||
# Boost
|
||||
RUN git clone -b boost-1.69.0 https://github.com/boostorg/boost.git \
|
||||
/usr/src/boost; \
|
||||
cd /usr/src/boost; \
|
||||
git submodule update --init --recursive; \
|
||||
./bootstrap.sh --with-toolset=clang --prefix=/usr; \
|
||||
./b2 toolset=clang cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" headers; \
|
||||
./b2 toolset=clang cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" \
|
||||
RUN set -ex; \
|
||||
cd /usr/src; \
|
||||
wget -q 'https://dl.bintray.com/boostorg/release/1.73.0/source/boost_1_73_0.tar.bz2' -O boost.tar.bz2; \
|
||||
test "$(sha256sum boost.tar.bz2)" = "4eb3b8d442b426dc35346235c8733b5ae35ba431690e38c6a8263dce9fcbb402 boost.tar.bz2"; \
|
||||
tar -xf boost.tar.bz2; \
|
||||
rm boost.tar.bz2; \
|
||||
cd boost_1_73_0; \
|
||||
CXXFLAGS="-stdlib=libc++ -pthread" LDFLAGS="-stdlib=libc++" ./bootstrap.sh --with-toolset=clang --prefix=/usr; \
|
||||
./b2 toolset=clang cxxflags="-stdlib=libc++ -pthread" linkflags="-stdlib=libc++ -pthread" headers; \
|
||||
./b2 toolset=clang cxxflags="-stdlib=libc++ -pthread" linkflags="-stdlib=libc++ -pthread" \
|
||||
link=static variant=release runtime-link=static \
|
||||
system filesystem unit_test_framework program_options \
|
||||
install -j $(($(nproc)/2)); \
|
||||
rm -rf /usr/src/boost
|
||||
rm -rf /usr/src/boost_1_73_0
|
||||
|
||||
# Z3
|
||||
RUN git clone --depth 1 -b z3-4.8.9 https://github.com/Z3Prover/z3.git \
|
||||
RUN set -ex; \
|
||||
git clone --depth 1 -b z3-4.8.9 https://github.com/Z3Prover/z3.git \
|
||||
/usr/src/z3; \
|
||||
cd /usr/src/z3; \
|
||||
mkdir build; \
|
||||
@ -109,23 +113,16 @@ RUN set -ex; \
|
||||
ninja install/strip; \
|
||||
rm -rf /usr/src/hera
|
||||
|
||||
# ANTLR4 RUNTIME
|
||||
# libabicoder
|
||||
RUN set -ex; \
|
||||
cd /usr/src; \
|
||||
wget https://www.antlr.org/download/antlr4-cpp-runtime-4.8-source.zip; \
|
||||
rm -rf antlr4-runtime && mkdir antlr4-runtime; \
|
||||
unzip antlr4-cpp-runtime-4.8-source.zip -d antlr4-runtime; \
|
||||
cd antlr4-runtime && mkdir build && cd build; \
|
||||
cmake .. -DWITH_LIBCXX=On -DCMAKE_BUILD_TYPE=Release -DWITH_DEMO=False; \
|
||||
make -j; \
|
||||
DESTDIR=run make install; \
|
||||
# Manually copy needed library and includes since install script
|
||||
# does not respect -DCMAKE_INSTALL_DIR and there is no option
|
||||
# to disable shared library build/installation
|
||||
cp -Rf run/usr/local/include/antlr4-runtime /usr/include; \
|
||||
cp -f run/usr/local/lib/libantlr4-runtime.a /usr/lib; \
|
||||
rm -rf /usr/src/antlr4-cpp-runtime-4.8-source.zip; \
|
||||
rm -rf /usr/src/antlr4-runtime
|
||||
git clone https://github.com/ekpyron/Yul-Isabelle; \
|
||||
cd Yul-Isabelle; \
|
||||
cd libabicoder; \
|
||||
CXX=clang++ CXXFLAGS="-stdlib=libc++ -pthread" make; \
|
||||
cp libabicoder.a /usr/lib; \
|
||||
cp abicoder.hpp /usr/include; \
|
||||
rm -rf /usr/src/Yul-Isabelle
|
||||
|
||||
FROM base
|
||||
COPY --from=libraries /usr/lib /usr/lib
|
||||
|
@ -220,7 +220,7 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False):
|
||||
return False
|
||||
|
||||
old_source_only_ids = {
|
||||
"1123", "1133", "1220", "1584", "1823", "1950",
|
||||
"1123", "1133", "1218", "1220", "1584", "1823", "1950",
|
||||
"1988", "2418", "2461", "2512", "2592", "2657", "2800", "2842", "2856",
|
||||
"3263", "3356", "3441", "3682", "3876",
|
||||
"3893", "4010", "4281", "4802", "4805", "4828",
|
||||
|
@ -1,9 +1,9 @@
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Needed for Invoke-WebRequest to work via CI.
|
||||
$progressPreference = "silentlyContinue"
|
||||
|
||||
if ( -not (Test-Path "$PSScriptRoot\..\deps\boost") ) {
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Needed for Invoke-WebRequest to work via CI.
|
||||
$progressPreference = "silentlyContinue"
|
||||
|
||||
New-Item -ItemType Directory -Force -Path "$PSScriptRoot\..\deps"
|
||||
|
||||
Invoke-WebRequest -URI "https://github.com/Kitware/CMake/releases/download/v3.18.2/cmake-3.18.2-win64-x64.zip" -OutFile cmake.zip
|
||||
|
@ -146,6 +146,7 @@ static string const g_strMachine = "machine";
|
||||
static string const g_strMetadata = "metadata";
|
||||
static string const g_strMetadataHash = "metadata-hash";
|
||||
static string const g_strMetadataLiteral = "metadata-literal";
|
||||
static string const g_strModelCheckerEngine = "model-checker-engine";
|
||||
static string const g_strNatspecDev = "devdoc";
|
||||
static string const g_strNatspecUser = "userdoc";
|
||||
static string const g_strNone = "none";
|
||||
@ -215,6 +216,7 @@ static string const g_argMachine = g_strMachine;
|
||||
static string const g_argMetadata = g_strMetadata;
|
||||
static string const g_argMetadataHash = g_strMetadataHash;
|
||||
static string const g_argMetadataLiteral = g_strMetadataLiteral;
|
||||
static string const g_argModelCheckerEngine = g_strModelCheckerEngine;
|
||||
static string const g_argNatspecDev = g_strNatspecDev;
|
||||
static string const g_argNatspecUser = g_strNatspecUser;
|
||||
static string const g_argOpcodes = g_strOpcodes;
|
||||
@ -993,6 +995,16 @@ General Information)").c_str(),
|
||||
;
|
||||
desc.add(optimizerOptions);
|
||||
|
||||
po::options_description smtCheckerOptions("Model Checker Options");
|
||||
smtCheckerOptions.add_options()
|
||||
(
|
||||
g_strModelCheckerEngine.c_str(),
|
||||
po::value<string>()->value_name("all,bmc,chc,none")->default_value("all"),
|
||||
"Select model checker engine."
|
||||
)
|
||||
;
|
||||
desc.add(smtCheckerOptions);
|
||||
|
||||
po::options_description allOptions = desc;
|
||||
allOptions.add_options()(g_argInputFile.c_str(), po::value<vector<string>>(), "input file");
|
||||
|
||||
@ -1379,6 +1391,18 @@ bool CommandLineInterface::processInput()
|
||||
}
|
||||
}
|
||||
|
||||
if (m_args.count(g_argModelCheckerEngine))
|
||||
{
|
||||
string engineStr = m_args[g_argModelCheckerEngine].as<string>();
|
||||
optional<ModelCheckerEngine> engine = ModelCheckerEngine::fromString(engineStr);
|
||||
if (!engine)
|
||||
{
|
||||
serr() << "Invalid option for --" << g_argModelCheckerEngine << ": " << engineStr << endl;
|
||||
return false;
|
||||
}
|
||||
m_modelCheckerEngine = *engine;
|
||||
}
|
||||
|
||||
m_compiler = make_unique<CompilerStack>(fileReader);
|
||||
|
||||
unique_ptr<SourceReferenceFormatter> formatter;
|
||||
@ -1393,6 +1417,8 @@ bool CommandLineInterface::processInput()
|
||||
m_compiler->useMetadataLiteralSources(true);
|
||||
if (m_args.count(g_argMetadataHash))
|
||||
m_compiler->setMetadataHash(m_metadataHash);
|
||||
if (m_args.count(g_argModelCheckerEngine))
|
||||
m_compiler->setModelCheckerEngine(m_modelCheckerEngine);
|
||||
if (m_args.count(g_argInputFile))
|
||||
m_compiler->setRemappings(m_remappings);
|
||||
|
||||
|
@ -79,7 +79,6 @@ private:
|
||||
void handleABI(std::string const& _contract);
|
||||
void handleNatspec(bool _natspecDev, std::string const& _contract);
|
||||
void handleGasEstimation(std::string const& _contract);
|
||||
void handleFormal();
|
||||
void handleStorageLayout(std::string const& _contract);
|
||||
|
||||
/// Fills @a m_sourceCodes initially and @a m_redirects.
|
||||
@ -134,6 +133,8 @@ private:
|
||||
RevertStrings m_revertStrings = RevertStrings::Default;
|
||||
/// Chosen hash method for the bytecode metadata.
|
||||
CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS;
|
||||
/// Chosen model checker engine.
|
||||
ModelCheckerEngine m_modelCheckerEngine = ModelCheckerEngine::All();
|
||||
/// Whether or not to colorize diagnostics output.
|
||||
bool m_coloredOutput = true;
|
||||
/// Whether or not to output error IDs.
|
||||
|
@ -9,7 +9,7 @@ IR:
|
||||
|
||||
object "C_80" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
constructor_C_80()
|
||||
@ -25,7 +25,7 @@ object "C_80" {
|
||||
}
|
||||
object "C_80_deployed" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ Optimized IR:
|
||||
object "C_6" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
let _1 := datasize("C_6_deployed")
|
||||
codecopy(0, dataoffset("C_6_deployed"), _1)
|
||||
@ -19,7 +19,7 @@ object "C_6" {
|
||||
object "C_6_deployed" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
@ -37,7 +37,7 @@ Optimized IR:
|
||||
object "D_9" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
let _1 := datasize("D_9_deployed")
|
||||
codecopy(0, dataoffset("D_9_deployed"), _1)
|
||||
@ -47,7 +47,7 @@ object "D_9" {
|
||||
object "D_9_deployed" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ Optimized IR:
|
||||
object "C_2" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
let _1 := datasize("C_2_deployed")
|
||||
codecopy(0, dataoffset("C_2_deployed"), _1)
|
||||
@ -19,7 +19,7 @@ object "C_2" {
|
||||
object "C_2_deployed" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
@ -37,7 +37,7 @@ Optimized IR:
|
||||
object "D_15" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
let _1 := datasize("D_15_deployed")
|
||||
codecopy(0, dataoffset("D_15_deployed"), _1)
|
||||
@ -47,21 +47,20 @@ object "D_15" {
|
||||
object "D_15_deployed" {
|
||||
code {
|
||||
{
|
||||
let _1 := memoryguard(0x80)
|
||||
mstore(64, _1)
|
||||
mstore(64, 128)
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
let _2 := 0
|
||||
if eq(0x26121ff0, shr(224, calldataload(_2)))
|
||||
let _1 := 0
|
||||
if eq(0x26121ff0, shr(224, calldataload(_1)))
|
||||
{
|
||||
if callvalue() { revert(_2, _2) }
|
||||
if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) }
|
||||
let _3 := datasize("C_2")
|
||||
let _4 := add(_1, _3)
|
||||
if or(gt(_4, 0xffffffffffffffff), lt(_4, _1)) { invalid() }
|
||||
datacopy(_1, dataoffset("C_2"), _3)
|
||||
pop(create(_2, _1, sub(_4, _1)))
|
||||
return(allocateMemory(_2), _2)
|
||||
if callvalue() { revert(_1, _1) }
|
||||
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||
let _2 := datasize("C_2")
|
||||
let _3 := add(128, _2)
|
||||
if or(gt(_3, 0xffffffffffffffff), lt(_3, 128)) { invalid() }
|
||||
datacopy(128, dataoffset("C_2"), _2)
|
||||
pop(create(_1, 128, _2))
|
||||
return(allocateMemory(_1), _1)
|
||||
}
|
||||
}
|
||||
revert(0, 0)
|
||||
@ -77,7 +76,7 @@ object "D_15" {
|
||||
object "C_2" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
let _1 := datasize("C_2_deployed")
|
||||
codecopy(0, dataoffset("C_2_deployed"), _1)
|
||||
@ -87,7 +86,7 @@ object "D_15" {
|
||||
object "C_2_deployed" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
|
@ -19,18 +19,16 @@ object "D_11" {
|
||||
object "D_11_deployed" {
|
||||
code {
|
||||
{
|
||||
let _1 := memoryguard(0x80)
|
||||
mstore(64, _1)
|
||||
mstore(64, 128)
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
let _2 := 0
|
||||
if eq(0x26121ff0, shr(224, calldataload(_2)))
|
||||
let _1 := 0
|
||||
if eq(0x26121ff0, shr(224, calldataload(_1)))
|
||||
{
|
||||
if callvalue() { revert(_2, _2) }
|
||||
if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) }
|
||||
if gt(_1, 0xffffffffffffffff) { invalid() }
|
||||
mstore(64, _1)
|
||||
return(_1, _2)
|
||||
if callvalue() { revert(_1, _1) }
|
||||
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||
mstore(64, 128)
|
||||
return(128, _1)
|
||||
}
|
||||
}
|
||||
revert(0, 0)
|
||||
|
@ -9,7 +9,7 @@ Optimized IR:
|
||||
object "D_7" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
let _1 := datasize("D_7_deployed")
|
||||
codecopy(0, dataoffset("D_7_deployed"), _1)
|
||||
|
1
test/cmdlineTests/model_checker_engine_all/args
Normal file
1
test/cmdlineTests/model_checker_engine_all/args
Normal file
@ -0,0 +1 @@
|
||||
--model-checker-engine all
|
13
test/cmdlineTests/model_checker_engine_all/err
Normal file
13
test/cmdlineTests/model_checker_engine_all/err
Normal file
@ -0,0 +1,13 @@
|
||||
Warning: CHC: Assertion violation happens here.
|
||||
--> model_checker_engine_all/input.sol:6:3:
|
||||
|
|
||||
6 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
|
||||
x = 0
|
||||
|
||||
|
||||
Transaction trace:
|
||||
constructor()
|
||||
f(0)
|
8
test/cmdlineTests/model_checker_engine_all/input.sol
Normal file
8
test/cmdlineTests/model_checker_engine_all/input.sol
Normal file
@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
function f(uint x) public pure {
|
||||
assert(x > 0);
|
||||
}
|
||||
}
|
1
test/cmdlineTests/model_checker_engine_bmc/args
Normal file
1
test/cmdlineTests/model_checker_engine_bmc/args
Normal file
@ -0,0 +1 @@
|
||||
--model-checker-engine bmc
|
10
test/cmdlineTests/model_checker_engine_bmc/err
Normal file
10
test/cmdlineTests/model_checker_engine_bmc/err
Normal file
@ -0,0 +1,10 @@
|
||||
Warning: BMC: Assertion violation happens here.
|
||||
--> model_checker_engine_bmc/input.sol:6:3:
|
||||
|
|
||||
6 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
x = 0
|
||||
|
||||
Note: Callstack:
|
||||
Note:
|
8
test/cmdlineTests/model_checker_engine_bmc/input.sol
Normal file
8
test/cmdlineTests/model_checker_engine_bmc/input.sol
Normal file
@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
function f(uint x) public pure {
|
||||
assert(x > 0);
|
||||
}
|
||||
}
|
1
test/cmdlineTests/model_checker_engine_chc/args
Normal file
1
test/cmdlineTests/model_checker_engine_chc/args
Normal file
@ -0,0 +1 @@
|
||||
--model-checker-engine chc
|
13
test/cmdlineTests/model_checker_engine_chc/err
Normal file
13
test/cmdlineTests/model_checker_engine_chc/err
Normal file
@ -0,0 +1,13 @@
|
||||
Warning: CHC: Assertion violation happens here.
|
||||
--> model_checker_engine_chc/input.sol:6:3:
|
||||
|
|
||||
6 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
|
||||
x = 0
|
||||
|
||||
|
||||
Transaction trace:
|
||||
constructor()
|
||||
f(0)
|
8
test/cmdlineTests/model_checker_engine_chc/input.sol
Normal file
8
test/cmdlineTests/model_checker_engine_chc/input.sol
Normal file
@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
function f(uint x) public pure {
|
||||
assert(x > 0);
|
||||
}
|
||||
}
|
1
test/cmdlineTests/model_checker_engine_none/args
Normal file
1
test/cmdlineTests/model_checker_engine_none/args
Normal file
@ -0,0 +1 @@
|
||||
--model-checker-engine none
|
5
test/cmdlineTests/model_checker_engine_none/err
Normal file
5
test/cmdlineTests/model_checker_engine_none/err
Normal file
@ -0,0 +1,5 @@
|
||||
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.
|
||||
--> model_checker_engine_none/input.sol
|
||||
|
||||
Warning: Source file does not specify required compiler version!
|
||||
--> model_checker_engine_none/input.sol
|
9
test/cmdlineTests/model_checker_engine_none/input.sol
Normal file
9
test/cmdlineTests/model_checker_engine_none/input.sol
Normal file
@ -0,0 +1,9 @@
|
||||
// Removed to yield a warning, otherwise CI test fails with the expectation
|
||||
// "no output requested"
|
||||
//pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
function f(uint x) public pure {
|
||||
assert(x > 0);
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@ Optimized IR:
|
||||
object "C_59" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
let _1 := datasize("C_59_deployed")
|
||||
codecopy(0, dataoffset("C_59_deployed"), _1)
|
||||
@ -19,7 +19,7 @@ object "C_59" {
|
||||
object "C_59_deployed" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
let _1 := 0
|
||||
|
@ -9,7 +9,7 @@ Optimized IR:
|
||||
object "Arraysum_33" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
let _1 := datasize("Arraysum_33_deployed")
|
||||
codecopy(0, dataoffset("Arraysum_33_deployed"), _1)
|
||||
@ -19,7 +19,7 @@ object "Arraysum_33" {
|
||||
object "Arraysum_33_deployed" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
let _1 := 0
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
object \"C_6\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
constructor_C_6()
|
||||
codecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))
|
||||
@ -17,7 +17,7 @@ object \"C_6\" {
|
||||
}
|
||||
object \"C_6_deployed\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
let selector := shift_right_224_unsigned(calldataload(0))
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
object \"C_6\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
constructor_C_6()
|
||||
@ -24,7 +24,7 @@ object \"C_6\" {
|
||||
}
|
||||
object \"C_6_deployed\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\npragma experimental SMTChecker;\ncontract C { function f(uint x) public pure { assert(x > 0); } }"
|
||||
}
|
||||
},
|
||||
"modelCheckerSettings":
|
||||
{
|
||||
"engine": "all"
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
{"errors":[{"component":"general","errorCode":"6328","formattedMessage":"A:4:47: Warning: CHC: Assertion violation happens here.
|
||||
contract C { function f(uint x) public pure { assert(x > 0); } }
|
||||
^-----------^
|
||||
Counterexample:
|
||||
|
||||
x = 0
|
||||
|
||||
|
||||
Transaction trace:
|
||||
constructor()
|
||||
f(0)
|
||||
","message":"CHC: Assertion violation happens here.","secondarySourceLocations":[{"message":"Counterexample:
|
||||
|
||||
x = 0
|
||||
|
||||
|
||||
Transaction trace:
|
||||
constructor()
|
||||
f(0)"}],"severity":"warning","sourceLocation":{"end":150,"file":"A","start":137},"type":"Warning"}],"sources":{"A":{"id":0}}}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\npragma experimental SMTChecker;\ncontract C { function f(uint x) public pure { assert(x > 0); } }"
|
||||
}
|
||||
},
|
||||
"modelCheckerSettings":
|
||||
{
|
||||
"engine": "bmc"
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
{"auxiliaryInputRequested":{"smtlib2queries":{"0x8b2c3058077c75f8fff85d2d387198b91b4e591448624f4bef0ab6c7b87d5ec1":"(set-option :produce-models true)
|
||||
(set-logic ALL)
|
||||
(declare-fun |error_0| () Int)
|
||||
(declare-fun |this_0| () Int)
|
||||
(declare-datatypes ((|state_type| 0)) (((|state_type| (|balances| (Array Int Int))))))
|
||||
(declare-fun |state_0| () |state_type|)
|
||||
(declare-datatypes ((|bytes_tuple| 0)) (((|bytes_tuple| (|bytes_tuple_accessor_array| (Array Int Int)) (|bytes_tuple_accessor_length| Int)))))
|
||||
(declare-datatypes ((|tx_type| 0)) (((|tx_type| (|block.coinbase| Int) (|block.difficulty| Int) (|block.gaslimit| Int) (|block.number| Int) (|block.timestamp| Int) (|blockhash| (Array Int Int)) (|msg.data| |bytes_tuple|) (|msg.sender| Int) (|msg.sig| Int) (|msg.value| Int) (|tx.gasprice| Int) (|tx.origin| Int)))))
|
||||
(declare-fun |tx_0| () |tx_type|)
|
||||
(declare-datatypes ((|ecrecover_input_type| 0)) (((|ecrecover_input_type| (|hash| Int) (|v| Int) (|r| Int) (|s| Int)))))
|
||||
(declare-datatypes ((|crypto_type| 0)) (((|crypto_type| (|ecrecover| (Array |ecrecover_input_type| Int)) (|keccak256| (Array |bytes_tuple| Int)) (|ripemd160| (Array |bytes_tuple| Int)) (|sha256| (Array |bytes_tuple| Int))))))
|
||||
(declare-fun |crypto_0| () |crypto_type|)
|
||||
(declare-fun |x_4_0| () Int)
|
||||
(declare-fun |expr_8_0| () Int)
|
||||
(declare-fun |expr_9_0| () Int)
|
||||
(declare-fun |expr_10_1| () Bool)
|
||||
|
||||
(assert (and (and true (and (= expr_10_1 (> expr_8_0 expr_9_0)) (and (= expr_9_0 0) (and (= expr_8_0 x_4_0) (and (and (>= x_4_0 0) (<= x_4_0 115792089237316195423570985008687907853269984665640564039457584007913129639935)) true))))) (not expr_10_1)))
|
||||
(declare-const |EVALEXPR_0| Int)
|
||||
(assert (= |EVALEXPR_0| x_4_0))
|
||||
(check-sat)
|
||||
(get-value (|EVALEXPR_0| ))
|
||||
"}},"errors":[{"component":"general","errorCode":"4661","formattedMessage":"A:4:47: Warning: BMC: Assertion violation happens here.
|
||||
contract C { function f(uint x) public pure { assert(x > 0); } }
|
||||
^-----------^
|
||||
Counterexample:
|
||||
x = 0
|
||||
|
||||
Callstack:
|
||||
|
||||
","message":"BMC: Assertion violation happens here.","secondarySourceLocations":[{"message":"Counterexample:
|
||||
x = 0
|
||||
"},{"message":"Callstack:"},{"message":""}],"severity":"warning","sourceLocation":{"end":150,"file":"A","start":137},"type":"Warning"}],"sources":{"A":{"id":0}}}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\npragma experimental SMTChecker;\ncontract C { function f(uint x) public pure { assert(x > 0); } }"
|
||||
}
|
||||
},
|
||||
"modelCheckerSettings":
|
||||
{
|
||||
"engine": "chc"
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
{"errors":[{"component":"general","errorCode":"6328","formattedMessage":"A:4:47: Warning: CHC: Assertion violation happens here.
|
||||
contract C { function f(uint x) public pure { assert(x > 0); } }
|
||||
^-----------^
|
||||
Counterexample:
|
||||
|
||||
x = 0
|
||||
|
||||
|
||||
Transaction trace:
|
||||
constructor()
|
||||
f(0)
|
||||
","message":"CHC: Assertion violation happens here.","secondarySourceLocations":[{"message":"Counterexample:
|
||||
|
||||
x = 0
|
||||
|
||||
|
||||
Transaction trace:
|
||||
constructor()
|
||||
f(0)"}],"severity":"warning","sourceLocation":{"end":150,"file":"A","start":137},"type":"Warning"}],"sources":{"A":{"id":0}}}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\npragma experimental SMTChecker;\ncontract C { function f(uint x) public pure { assert(x > 0); } }"
|
||||
}
|
||||
},
|
||||
"modelCheckerSettings":
|
||||
{
|
||||
"engine": "none"
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"sources":{"A":{"id":0}}}
|
@ -9,7 +9,7 @@ Optimized IR:
|
||||
object "C_6" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
codecopy(0, dataoffset("C_6_deployed"), datasize("C_6_deployed"))
|
||||
return(0, datasize("C_6_deployed"))
|
||||
@ -18,7 +18,7 @@ object "C_6" {
|
||||
object "C_6_deployed" {
|
||||
code {
|
||||
{
|
||||
mstore(64, memoryguard(0x80))
|
||||
mstore(64, 128)
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
let selector := shift_right_224_unsigned(calldataload(0))
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
constructor_C_10()
|
||||
@ -24,7 +24,7 @@ object \"C_10\" {
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
constructor_C_10()
|
||||
@ -24,7 +24,7 @@ object \"C_10\" {
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
constructor_C_10()
|
||||
@ -24,7 +24,7 @@ object \"C_10\" {
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
constructor_C_10()
|
||||
@ -24,7 +24,7 @@ object \"C_10\" {
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
object \"C_10\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
if callvalue() { revert(0, 0) }
|
||||
|
||||
constructor_C_10()
|
||||
@ -24,7 +24,7 @@ object \"C_10\" {
|
||||
}
|
||||
object \"C_10_deployed\" {
|
||||
code {
|
||||
mstore(64, memoryguard(128))
|
||||
mstore(64, 128)
|
||||
|
||||
if iszero(lt(calldatasize(), 4))
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
Error (1834): Unimplemented feature error: Byte Arrays not yet implemented! in FILENAME REMOVED
|
||||
--> yul_unimplemented/input.sol:6:9:
|
||||
Error (1834): Unimplemented feature error: Copying from storage to storage is not yet implemented. in FILENAME REMOVED
|
||||
--> yul_unimplemented/input.sol:7:9:
|
||||
|
|
||||
6 | delete a;
|
||||
| ^^^^^^^^
|
||||
7 | a = b;
|
||||
| ^^^^^
|
||||
|
@ -2,7 +2,8 @@
|
||||
pragma solidity >=0.0;
|
||||
contract test {
|
||||
bytes a;
|
||||
bytes b;
|
||||
function f() public {
|
||||
delete a;
|
||||
a = b;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
contract C {
|
||||
function f(bytes calldata x) public returns (C[] memory) {
|
||||
return abi.decode(x, (C[]));
|
||||
}
|
||||
function g() public returns (bytes memory) {
|
||||
C[] memory c = new C[](3);
|
||||
c[0] = C(address(0x42));
|
||||
c[1] = C(address(0x21));
|
||||
c[2] = C(address(0x23));
|
||||
return abi.encode(c);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bytes): 0x20, 0xA0, 0x20, 3, 0x01, 0x02, 0x03 -> 0x20, 3, 0x01, 0x02, 0x03
|
||||
// g() -> 0x20, 0xa0, 0x20, 3, 0x42, 0x21, 0x23
|
@ -0,0 +1,20 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
contract C {
|
||||
function f(bytes calldata x) public returns (C[] memory) {
|
||||
return abi.decode(x, (C[]));
|
||||
}
|
||||
function g() public returns (bytes memory) {
|
||||
C[] memory c = new C[](3);
|
||||
c[0] = C(address(0x42));
|
||||
c[1] = C(address(0x21));
|
||||
c[2] = C(address(0x23));
|
||||
return abi.encode(c);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bytes): 0x20, 0xA0, 0x20, 3, 0x01, 0x02, 0x03 -> 0x20, 3, 0x01, 0x02, 0x03
|
||||
// f(bytes): 0x20, 0x60, 0x20, 1, 0x0102030405060708090a0b0c0d0e0f1011121314 -> 0x20, 1, 0x0102030405060708090a0b0c0d0e0f1011121314
|
||||
// f(bytes): 0x20, 0x60, 0x20, 1, 0x0102030405060708090a0b0c0d0e0f101112131415 -> FAILURE
|
||||
// g() -> 0x20, 0xa0, 0x20, 3, 0x42, 0x21, 0x23
|
@ -32,6 +32,7 @@ contract c {
|
||||
data.push(bytes1(i));
|
||||
}
|
||||
data.pop();
|
||||
data.pop();
|
||||
assembly {
|
||||
r := sload(data.slot)
|
||||
}
|
||||
@ -42,4 +43,4 @@ contract c {
|
||||
// ----
|
||||
// test_short() -> 1780731860627700044960722568376587075150542249149356309979516913770823710
|
||||
// test_long() -> 67
|
||||
// test_pop() -> 1780731860627700044960722568376592200742329637303199754547598369979440702
|
||||
// test_pop() -> 1780731860627700044960722568376592200742329637303199754547598369979433020
|
||||
|
37
test/libsolidity/semanticTests/array/delete_bytes_array.sol
Normal file
37
test/libsolidity/semanticTests/array/delete_bytes_array.sol
Normal file
@ -0,0 +1,37 @@
|
||||
contract C {
|
||||
bytes data;
|
||||
|
||||
function f() public returns (uint ret) {
|
||||
data.push("a");
|
||||
data.push("b");
|
||||
delete data;
|
||||
assembly {
|
||||
ret := sload(data.slot)
|
||||
}
|
||||
}
|
||||
|
||||
function g() public returns (uint ret) {
|
||||
assembly {
|
||||
sstore(data.slot, 67)
|
||||
}
|
||||
data.push("a");
|
||||
data.push("b");
|
||||
assert(data.length == 35);
|
||||
delete data;
|
||||
assert(data.length == 0);
|
||||
|
||||
uint size = 999;
|
||||
assembly {
|
||||
size := sload(data.slot)
|
||||
mstore(0, data.slot)
|
||||
ret := sload(keccak256(0, 32))
|
||||
}
|
||||
assert(size == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0
|
||||
// g() -> 0
|
@ -1,53 +0,0 @@
|
||||
contract C {
|
||||
uint256[1024] s;
|
||||
function f() public returns (uint256 x) {
|
||||
x = 42;
|
||||
uint256 x0 = s[0];
|
||||
uint256 x1 = s[1];
|
||||
uint256 x2 = s[2];
|
||||
uint256 x3 = s[3];
|
||||
uint256 x4 = s[4];
|
||||
uint256 x5 = s[5];
|
||||
uint256 x6 = s[6];
|
||||
uint256 x7 = s[7];
|
||||
uint256 x8 = s[8];
|
||||
uint256 x9 = s[9];
|
||||
uint256 x10 = s[10];
|
||||
uint256 x11 = s[11];
|
||||
uint256 x12 = s[12];
|
||||
uint256 x13 = s[13];
|
||||
uint256 x14 = s[14];
|
||||
uint256 x15 = s[15];
|
||||
uint256 x16 = s[16];
|
||||
uint256 x17 = s[17];
|
||||
uint256 x18 = s[18];
|
||||
s[1000] = x0 + 2;
|
||||
s[118] = x18;
|
||||
s[117] = x17;
|
||||
s[116] = x16;
|
||||
s[115] = x15;
|
||||
s[114] = x14;
|
||||
s[113] = x13;
|
||||
s[112] = x12;
|
||||
s[111] = x11;
|
||||
s[110] = x10;
|
||||
s[109] = x9;
|
||||
s[108] = x8;
|
||||
s[107] = x7;
|
||||
s[106] = x6;
|
||||
s[105] = x5;
|
||||
s[104] = x4;
|
||||
s[103] = x3;
|
||||
s[102] = x2;
|
||||
s[101] = x1;
|
||||
s[100] = x0;
|
||||
}
|
||||
function test() public view returns(uint256) {
|
||||
return s[1000];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> 0x2a
|
||||
// test() -> 2
|
@ -1,57 +0,0 @@
|
||||
contract C {
|
||||
uint256[1024] s;
|
||||
function g() public returns (uint256) {
|
||||
// try to prevent inlining
|
||||
return f() + f() + f() + f() + f();
|
||||
}
|
||||
function f() public returns (uint256 x) {
|
||||
x = 42;
|
||||
uint256 x0 = s[0];
|
||||
uint256 x1 = s[1];
|
||||
uint256 x2 = s[2];
|
||||
uint256 x3 = s[3];
|
||||
uint256 x4 = s[4];
|
||||
uint256 x5 = s[5];
|
||||
uint256 x6 = s[6];
|
||||
uint256 x7 = s[7];
|
||||
uint256 x8 = s[8];
|
||||
uint256 x9 = s[9];
|
||||
uint256 x10 = s[10];
|
||||
uint256 x11 = s[11];
|
||||
uint256 x12 = s[12];
|
||||
uint256 x13 = s[13];
|
||||
uint256 x14 = s[14];
|
||||
uint256 x15 = s[15];
|
||||
uint256 x16 = s[16];
|
||||
uint256 x17 = s[17];
|
||||
uint256 x18 = s[18];
|
||||
s[1000] = x0 + 2;
|
||||
s[118] = x18;
|
||||
s[117] = x17;
|
||||
s[116] = x16;
|
||||
s[115] = x15;
|
||||
s[114] = x14;
|
||||
s[113] = x13;
|
||||
s[112] = x12;
|
||||
s[111] = x11;
|
||||
s[110] = x10;
|
||||
s[109] = x9;
|
||||
s[108] = x8;
|
||||
s[107] = x7;
|
||||
s[106] = x6;
|
||||
s[105] = x5;
|
||||
s[104] = x4;
|
||||
s[103] = x3;
|
||||
s[102] = x2;
|
||||
s[101] = x1;
|
||||
s[100] = x0;
|
||||
}
|
||||
function test() public view returns(uint256) {
|
||||
return s[1000];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> 0x2a
|
||||
// test() -> 2
|
@ -0,0 +1,16 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
function f(bytes memory data) public pure {
|
||||
bytes32 k = keccak256(data);
|
||||
bytes32 s = sha256(data);
|
||||
bytes32 r = ripemd160(data);
|
||||
assert(k == s);
|
||||
assert(s == r);
|
||||
assert(r == k);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (183-197): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (201-215): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (219-233): CHC: Assertion violation happens here.
|
@ -0,0 +1,32 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
function k(bytes memory b0, bytes memory b1) public pure {
|
||||
bytes32 k0 = keccak256(b0);
|
||||
bytes32 k1 = keccak256(b1);
|
||||
assert(k0 == k1);
|
||||
}
|
||||
function s(bytes memory b0, bytes memory b1) public pure {
|
||||
bytes32 s0 = sha256(b0);
|
||||
bytes32 s1 = sha256(b1);
|
||||
assert(s0 == s1);
|
||||
}
|
||||
function r(bytes memory b0, bytes memory b1) public pure {
|
||||
bytes32 r0 = ripemd160(b0);
|
||||
bytes32 r1 = ripemd160(b1);
|
||||
assert(r0 == r1);
|
||||
}
|
||||
function e(bytes32 h0, uint8 v0, bytes32 r0, bytes32 s0, bytes32 h1, uint8 v1, bytes32 r1, bytes32 s1) public pure {
|
||||
address a0 = ecrecover(h0, v0, r0, s0);
|
||||
address a1 = ecrecover(h1, v1, r1, s1);
|
||||
assert(a0 == a1);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (168-184): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (305-321): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (448-464): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 6328: (673-689): CHC: Assertion violation happens here.
|
||||
// Warning 4661: (168-184): BMC: Assertion violation happens here.
|
||||
// Warning 4661: (305-321): BMC: Assertion violation happens here.
|
||||
// Warning 4661: (448-464): BMC: Assertion violation happens here.
|
@ -0,0 +1,14 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
function f(bytes memory data) public pure {
|
||||
bytes32 k = keccak256(data);
|
||||
fi(data, k);
|
||||
}
|
||||
function fi(bytes memory data, bytes32 k) internal pure {
|
||||
bytes32 h = sha256(data);
|
||||
assert(h == k);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (229-243): CHC: Assertion violation happens here.
|
@ -0,0 +1,12 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
function f(bytes memory data) public pure {
|
||||
bytes32 k = keccak256(data);
|
||||
fi(data, k);
|
||||
}
|
||||
function fi(bytes memory data, bytes32 k) internal pure {
|
||||
bytes32 h = keccak256(data);
|
||||
assert(h == k);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
bytes data;
|
||||
bytes32 h;
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
|
||||
bytes32 kec;
|
||||
bytes32 sha;
|
||||
bytes32 rip;
|
||||
address erc;
|
||||
|
||||
constructor(bytes memory _data, bytes32 _h, uint8 _v, bytes32 _r, bytes32 _s) {
|
||||
data = _data;
|
||||
h = _h;
|
||||
v = _v;
|
||||
r = _r;
|
||||
s = _s;
|
||||
|
||||
kec = keccak256(data);
|
||||
sha = sha256(data);
|
||||
rip = ripemd160(data);
|
||||
erc = ecrecover(h, v, r, s);
|
||||
}
|
||||
|
||||
function f() public view {
|
||||
bytes32 _kec = keccak256(data);
|
||||
bytes32 _sha = sha256(data);
|
||||
bytes32 _rip = ripemd160(data);
|
||||
address _erc = ecrecover(h, v, r, s);
|
||||
assert(_kec == kec);
|
||||
assert(_sha == sha);
|
||||
assert(_rip == rip);
|
||||
assert(_erc == erc);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
bytes data;
|
||||
bytes32 h;
|
||||
uint8 v;
|
||||
bytes32 r;
|
||||
bytes32 s;
|
||||
|
||||
bytes32 kec;
|
||||
bytes32 sha;
|
||||
bytes32 rip;
|
||||
address erc;
|
||||
|
||||
constructor(bytes memory _data, bytes32 _h, uint8 _v, bytes32 _r, bytes32 _s) {
|
||||
data = _data;
|
||||
h = _h;
|
||||
v = _v;
|
||||
r = _r;
|
||||
s = _s;
|
||||
|
||||
kec = keccak256(data);
|
||||
sha = sha256(data);
|
||||
rip = ripemd160(data);
|
||||
erc = ecrecover(h, v, r, s);
|
||||
}
|
||||
|
||||
function set(bytes memory _data, bytes32 _h, uint8 _v, bytes32 _r, bytes32 _s) public {
|
||||
data = _data;
|
||||
h = _h;
|
||||
v = _v;
|
||||
r = _r;
|
||||
s = _s;
|
||||
}
|
||||
|
||||
function f() public view {
|
||||
bytes32 _kec = keccak256(data);
|
||||
bytes32 _sha = sha256(data);
|
||||
bytes32 _rip = ripemd160(data);
|
||||
address _erc = ecrecover(h, v, r, s);
|
||||
assert(_kec == kec);
|
||||
assert(_sha == sha);
|
||||
assert(_rip == rip);
|
||||
assert(_erc == erc);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (726-745): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (749-768): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (772-791): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 6328: (795-814): CHC: Assertion violation happens here.
|
||||
// Warning 4661: (726-745): BMC: Assertion violation happens here.
|
||||
// Warning 4661: (749-768): BMC: Assertion violation happens here.
|
||||
// Warning 4661: (772-791): BMC: Assertion violation happens here.
|
@ -0,0 +1,28 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
function k(bytes memory b0) public pure {
|
||||
bytes memory b1 = b0;
|
||||
bytes32 k0 = keccak256(b0);
|
||||
bytes32 k1 = keccak256(b1);
|
||||
assert(k0 == k1);
|
||||
}
|
||||
function s(bytes memory b0) public pure {
|
||||
bytes memory b1 = b0;
|
||||
bytes32 s0 = sha256(b0);
|
||||
bytes32 s1 = sha256(b1);
|
||||
assert(s0 == s1);
|
||||
}
|
||||
function r(bytes memory b0) public pure {
|
||||
bytes memory b1 = b0;
|
||||
bytes32 r0 = ripemd160(b0);
|
||||
bytes32 r1 = ripemd160(b1);
|
||||
assert(r0 == r1);
|
||||
}
|
||||
function e(bytes32 h0, uint8 v0, bytes32 r0, bytes32 s0) public pure {
|
||||
(bytes32 h1, uint8 v1, bytes32 r1, bytes32 s1) = (h0, v0, r0, s0);
|
||||
address a0 = ecrecover(h0, v0, r0, s0);
|
||||
address a1 = ecrecover(h1, v1, r1, s1);
|
||||
assert(a0 == a1);
|
||||
}
|
||||
}
|
@ -12,7 +12,8 @@ contract Simple {
|
||||
++x;
|
||||
assert(x == 10);
|
||||
}
|
||||
assert(y == x);
|
||||
// Removed because of Spacer nondeterminism.
|
||||
//assert(y == x);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
|
@ -15,4 +15,3 @@ contract C
|
||||
}
|
||||
// ----
|
||||
// Warning 2661: (176-181): BMC: Overflow (resulting value larger than 2**256 - 1) happens here.
|
||||
// Warning 4661: (296-309): BMC: Assertion violation happens here.
|
||||
|
@ -12,10 +12,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (83-108): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (141-166): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (76-114): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (170-184): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (263-278): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 3046: (141-166): BMC: Division by zero happens here.
|
||||
// Warning 3046: (263-278): BMC: Division by zero happens here.
|
||||
|
@ -9,8 +9,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (118-143): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (183-208): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (219-233): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 6838: (93-143): BMC: Condition is always false.
|
||||
// Warning 6838: (158-208): BMC: Condition is always false.
|
||||
|
@ -22,15 +22,5 @@ contract C {
|
||||
}
|
||||
// ----
|
||||
// Warning 6321: (253-260): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable.
|
||||
// Warning 1218: (94-109): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (113-126): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (180-195): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (199-212): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (275-290): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (303-318): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (349-364): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (377-392): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (322-336): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (396-410): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 3046: (94-109): BMC: Division by zero happens here.
|
||||
// Warning 3046: (180-195): BMC: Division by zero happens here.
|
||||
|
@ -17,8 +17,3 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (158-174): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (178-192): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (309-325): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (329-343): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 7812: (329-343): BMC: Assertion violation might happen here.
|
||||
|
@ -12,10 +12,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (83-108): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (141-166): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (76-114): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (170-184): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (263-278): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 3046: (141-166): BMC: Division by zero happens here.
|
||||
// Warning 3046: (263-278): BMC: Division by zero happens here.
|
||||
|
@ -9,6 +9,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (129-143): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (147-161): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 4661: (147-161): BMC: Assertion violation happens here.
|
||||
// Warning 6328: (147-161): CHC: Assertion violation happens here.
|
||||
|
@ -10,6 +10,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (163-184): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (188-209): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 4661: (188-209): BMC: Assertion violation happens here.
|
||||
// Warning 6328: (188-209): CHC: Assertion violation happens here.
|
||||
|
@ -10,6 +10,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (171-190): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 1218: (194-213): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 4661: (194-213): BMC: Assertion violation happens here.
|
||||
// Warning 6328: (194-213): CHC: Assertion violation happens here.
|
||||
|
@ -6,5 +6,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (127-132): CHC: Error trying to invoke SMT solver.
|
||||
// Warning 2661: (127-132): BMC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here.
|
||||
// Warning 4984: (127-132): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here.
|
||||
|
@ -7,4 +7,3 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (147-152): CHC: Error trying to invoke SMT solver.
|
||||
|
@ -10,4 +10,3 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (151-156): CHC: Error trying to invoke SMT solver.
|
||||
|
@ -12,4 +12,3 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (265-270): CHC: Error trying to invoke SMT solver.
|
||||
|
@ -7,4 +7,3 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 1218: (107-125): CHC: Error trying to invoke SMT solver.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user