mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10033 from ethereum/develop
Merge develop into breaking
This commit is contained in:
commit
979d3062bc
@ -22,12 +22,15 @@ Language Features:
|
||||
|
||||
Compiler Features:
|
||||
* 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.
|
||||
|
||||
|
||||
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: 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.
|
||||
|
@ -3006,8 +3006,11 @@ TypePointers FunctionType::returnParameterTypesWithoutDynamicTypes() const
|
||||
m_kind == Kind::BareStaticCall
|
||||
)
|
||||
for (auto& param: returnParameterTypes)
|
||||
if (param->isDynamicallyEncoded() && !param->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
solAssert(param->decodingType(), "");
|
||||
if (param->decodingType()->isDynamicallyEncoded())
|
||||
param = TypeProvider::inaccessibleDynamic();
|
||||
}
|
||||
|
||||
return returnParameterTypes;
|
||||
}
|
||||
|
@ -170,7 +170,16 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
||||
// pop offset
|
||||
m_context << Instruction::POP;
|
||||
utils().copyToStackTop(paramTypes.size() - i + 1, 1);
|
||||
ArrayUtils(m_context).accessIndex(*arrayType);
|
||||
|
||||
ArrayUtils(m_context).retrieveLength(*arrayType, 1);
|
||||
// Stack: ref [length] index length
|
||||
// check out-of-bounds access
|
||||
m_context << Instruction::DUP2 << Instruction::LT;
|
||||
auto tag = m_context.appendConditionalJump();
|
||||
m_context << u256(0) << Instruction::DUP1 << Instruction::REVERT;
|
||||
m_context << tag;
|
||||
|
||||
ArrayUtils(m_context).accessIndex(*arrayType, false);
|
||||
returnType = arrayType->baseType();
|
||||
}
|
||||
else
|
||||
|
@ -41,16 +41,17 @@ ReturnInfo::ReturnInfo(EVMVersion const& _evmVersion, FunctionType const& _funct
|
||||
returnTypes = _functionType.returnParameterTypesWithoutDynamicTypes();
|
||||
|
||||
for (auto const& retType: returnTypes)
|
||||
if (retType->isDynamicallyEncoded())
|
||||
{
|
||||
solAssert(retType->decodingType(), "");
|
||||
if (retType->decodingType()->isDynamicallyEncoded())
|
||||
{
|
||||
solAssert(haveReturndatacopy, "");
|
||||
dynamicReturnSize = true;
|
||||
estimatedReturnSize = 0;
|
||||
break;
|
||||
}
|
||||
else if (retType->decodingType())
|
||||
estimatedReturnSize += retType->decodingType()->calldataEncodedSize();
|
||||
else
|
||||
estimatedReturnSize += retType->calldataEncodedSize();
|
||||
estimatedReturnSize += retType->decodingType()->calldataEncodedSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -918,7 +918,7 @@ string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type)
|
||||
string functionName = "array_length_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
Whiskers w(R"(
|
||||
function <functionName>(value) -> length {
|
||||
function <functionName>(value<?dynamic><?calldata>, len</calldata></dynamic>) -> length {
|
||||
<?dynamic>
|
||||
<?memory>
|
||||
length := mload(value)
|
||||
@ -929,6 +929,9 @@ string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type)
|
||||
length := <extractByteArrayLength>(length)
|
||||
</byteArray>
|
||||
</storage>
|
||||
<?calldata>
|
||||
length := len
|
||||
</calldata>
|
||||
<!dynamic>
|
||||
length := <length>
|
||||
</dynamic>
|
||||
@ -940,17 +943,14 @@ string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type)
|
||||
w("length", toCompactHexWithPrefix(_type.length()));
|
||||
w("memory", _type.location() == DataLocation::Memory);
|
||||
w("storage", _type.location() == DataLocation::Storage);
|
||||
w("calldata", _type.location() == DataLocation::CallData);
|
||||
if (_type.location() == DataLocation::Storage)
|
||||
{
|
||||
w("byteArray", _type.isByteArray());
|
||||
if (_type.isByteArray())
|
||||
w("extractByteArrayLength", extractByteArrayLengthFunction());
|
||||
}
|
||||
if (_type.isDynamicallySized())
|
||||
solAssert(
|
||||
_type.location() != DataLocation::CallData,
|
||||
"called regular array length function on calldata array"
|
||||
);
|
||||
|
||||
return w.render();
|
||||
});
|
||||
}
|
||||
@ -1295,6 +1295,105 @@ string YulUtilFunctions::clearStorageStructFunction(StructType const& _type)
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::copyArrayToStorage(ArrayType const& _fromType, ArrayType const& _toType)
|
||||
{
|
||||
solAssert(
|
||||
*_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast<ReferenceType const&>(_toType),
|
||||
""
|
||||
);
|
||||
solUnimplementedAssert(!_fromType.isByteArray(), "");
|
||||
solUnimplementedAssert(!_fromType.dataStoredIn(DataLocation::Storage), "");
|
||||
|
||||
string functionName = "copy_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&](){
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(slot, value<?isFromDynamicCalldata>, len</isFromDynamicCalldata>) {
|
||||
let length := <arrayLength>(value<?isFromDynamicCalldata>, len</isFromDynamicCalldata>)
|
||||
<?isToDynamic>
|
||||
<resizeArray>(slot, length)
|
||||
</isToDynamic>
|
||||
|
||||
let srcPtr :=
|
||||
<?isFromMemoryDynamic>
|
||||
add(value, 0x20)
|
||||
<!isFromMemoryDynamic>
|
||||
value
|
||||
</isFromMemoryDynamic>
|
||||
|
||||
let elementSlot := <dstDataLocation>(slot)
|
||||
let elementOffset := 0
|
||||
|
||||
for { let i := 0 } lt(i, length) {i := add(i, 1)} {
|
||||
<?fromCalldata>
|
||||
let <elementValues> :=
|
||||
<?dynamicallyEncodedBase>
|
||||
<accessCalldataTail>(value, srcPtr)
|
||||
<!dynamicallyEncodedBase>
|
||||
srcPtr
|
||||
</dynamicallyEncodedBase>
|
||||
|
||||
<?isValueType>
|
||||
<elementValues> := <readFromCalldataOrMemory>(<elementValues>)
|
||||
</isValueType>
|
||||
</fromCalldata>
|
||||
|
||||
<?fromMemory>
|
||||
let <elementValues> := <readFromCalldataOrMemory>(srcPtr)
|
||||
</fromMemory>
|
||||
|
||||
<updateStorageValue>(elementSlot<?isValueType>, elementOffset</isValueType>, <elementValues>)
|
||||
|
||||
srcPtr := add(srcPtr, <stride>)
|
||||
|
||||
<?multipleItemsPerSlot>
|
||||
elementOffset := add(elementOffset, <storageStride>)
|
||||
if gt(elementOffset, sub(32, <storageStride>)) {
|
||||
elementOffset := 0
|
||||
elementSlot := add(elementSlot, 1)
|
||||
}
|
||||
<!multipleItemsPerSlot>
|
||||
elementSlot := add(elementSlot, <storageSize>)
|
||||
elementOffset := 0
|
||||
</multipleItemsPerSlot>
|
||||
}
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
bool fromCalldata = _fromType.dataStoredIn(DataLocation::CallData);
|
||||
templ("isFromDynamicCalldata", _fromType.isDynamicallySized() && fromCalldata);
|
||||
templ("fromMemory", _fromType.dataStoredIn(DataLocation::Memory));
|
||||
templ("fromCalldata", fromCalldata);
|
||||
templ("isToDynamic", _toType.isDynamicallySized());
|
||||
templ("isFromMemoryDynamic", _fromType.isDynamicallySized() && _fromType.dataStoredIn(DataLocation::Memory));
|
||||
if (fromCalldata)
|
||||
{
|
||||
templ("dynamicallySizedBase", _fromType.baseType()->isDynamicallySized());
|
||||
templ("dynamicallyEncodedBase", _fromType.baseType()->isDynamicallyEncoded());
|
||||
if (_fromType.baseType()->isDynamicallyEncoded())
|
||||
templ("accessCalldataTail", accessCalldataTailFunction(*_fromType.baseType()));
|
||||
}
|
||||
if (_toType.isDynamicallySized())
|
||||
templ("resizeArray", resizeDynamicArrayFunction(_toType));
|
||||
templ("arrayLength",arrayLengthFunction(_fromType));
|
||||
templ("isValueType", _fromType.baseType()->isValueType());
|
||||
templ("dstDataLocation", arrayDataAreaFunction(_toType));
|
||||
if (!fromCalldata || _fromType.baseType()->isValueType())
|
||||
templ("readFromCalldataOrMemory", readFromMemoryOrCalldata(*_fromType.baseType(), fromCalldata));
|
||||
templ("elementValues", suffixedVariableNameList(
|
||||
"elementValue_",
|
||||
0,
|
||||
_fromType.baseType()->stackItems().size()
|
||||
));
|
||||
templ("updateStorageValue", updateStorageValueFunction(*_fromType.baseType(), *_toType.baseType()));
|
||||
templ("stride", to_string(fromCalldata ? _fromType.calldataStride() : _fromType.memoryStride()));
|
||||
templ("multipleItemsPerSlot", _toType.storageStride() <= 16);
|
||||
templ("storageStride", to_string(_toType.storageStride()));
|
||||
templ("storageSize", _toType.baseType()->storageSize().str());
|
||||
|
||||
return templ.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type)
|
||||
{
|
||||
string functionName = "array_convert_length_to_size_" + _type.identifier();
|
||||
@ -1865,23 +1964,39 @@ string YulUtilFunctions::updateStorageValueFunction(
|
||||
else
|
||||
{
|
||||
auto const* toReferenceType = dynamic_cast<ReferenceType const*>(&_toType);
|
||||
auto const* fromReferenceType = dynamic_cast<ReferenceType const*>(&_toType);
|
||||
auto const* fromReferenceType = dynamic_cast<ReferenceType const*>(&_fromType);
|
||||
solAssert(fromReferenceType && toReferenceType, "");
|
||||
solAssert(*toReferenceType->copyForLocation(
|
||||
fromReferenceType->location(),
|
||||
fromReferenceType->isPointer()
|
||||
).get() == *fromReferenceType, "");
|
||||
solUnimplementedAssert(fromReferenceType->location() != DataLocation::Storage, "");
|
||||
solAssert(toReferenceType->category() == fromReferenceType->category(), "");
|
||||
|
||||
if (_toType.category() == Type::Category::Array)
|
||||
solUnimplementedAssert(false, "");
|
||||
{
|
||||
solAssert(_offset.value_or(0) == 0, "");
|
||||
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(slot, <value>) {
|
||||
<copyArrayToStorage>(slot, <value>)
|
||||
}
|
||||
)");
|
||||
templ("functionName", functionName);
|
||||
templ("value", suffixedVariableNameList("value_", 0, _fromType.sizeOnStack()));
|
||||
templ("copyArrayToStorage", copyArrayToStorage(
|
||||
dynamic_cast<ArrayType const&>(_fromType),
|
||||
dynamic_cast<ArrayType const&>(_toType)
|
||||
));
|
||||
|
||||
return templ.render();
|
||||
}
|
||||
else if (_toType.category() == Type::Category::Struct)
|
||||
{
|
||||
solAssert(_fromType.category() == Type::Category::Struct, "");
|
||||
auto const& fromStructType = dynamic_cast<StructType const&>(_fromType);
|
||||
auto const& toStructType = dynamic_cast<StructType const&>(_toType);
|
||||
solAssert(fromStructType.structDefinition() == toStructType.structDefinition(), "");
|
||||
solAssert(fromStructType.location() != DataLocation::Storage, "");
|
||||
solUnimplementedAssert(_offset.has_value() && _offset.value() == 0, "");
|
||||
solAssert(_offset.value_or(0) == 0, "");
|
||||
|
||||
Whiskers templ(R"(
|
||||
function <functionName>(slot, value) {
|
||||
@ -1895,6 +2010,7 @@ string YulUtilFunctions::updateStorageValueFunction(
|
||||
templ("functionName", functionName);
|
||||
|
||||
MemberList::MemberMap structMembers = fromStructType.nativeMembers(nullptr);
|
||||
MemberList::MemberMap toStructMembers = toStructType.nativeMembers(nullptr);
|
||||
|
||||
vector<map<string, string>> memberParams(structMembers.size());
|
||||
for (size_t i = 0; i < structMembers.size(); ++i)
|
||||
@ -1902,31 +2018,65 @@ string YulUtilFunctions::updateStorageValueFunction(
|
||||
solAssert(structMembers[i].type->memoryHeadSize() == 32, "");
|
||||
bool fromCalldata = fromStructType.location() == DataLocation::CallData;
|
||||
auto const& [slotDiff, offset] = toStructType.storageOffsetsOfMember(structMembers[i].name);
|
||||
memberParams[i]["updateMemberCall"] = Whiskers(R"(
|
||||
let <memberValues> := <loadFromMemoryOrCalldata>(add(value, <memberOffset>))
|
||||
<updateMember>(add(slot, <memberStorageSlotDiff>), <?hasOffset><memberStorageOffset>,</hasOffset> <memberValues>)
|
||||
)")
|
||||
("memberValues", suffixedVariableNameList(
|
||||
|
||||
Whiskers t(R"(
|
||||
let memberSlot := add(slot, <memberStorageSlotDiff>)
|
||||
|
||||
<?fromCalldata>
|
||||
<?dynamicallyEncodedMember>
|
||||
let <memberCalldataOffset> := <accessCalldataTail>(value, add(value, <memberOffset>))
|
||||
<!dynamicallyEncodedMember>
|
||||
let <memberCalldataOffset> := add(value, <memberOffset>)
|
||||
</dynamicallyEncodedMember>
|
||||
|
||||
<?isValueType>
|
||||
let <memberValues> := <loadFromMemoryOrCalldata>(<memberCalldataOffset>)
|
||||
<updateMember>(memberSlot, <memberStorageOffset>, <memberValues>)
|
||||
<!isValueType>
|
||||
<updateMember>(memberSlot, <memberCalldataOffset>)
|
||||
</isValueType>
|
||||
<!fromCalldata>
|
||||
let memberMemoryOffset := add(value, <memberOffset>)
|
||||
let <memberValues> := <loadFromMemoryOrCalldata>(memberMemoryOffset)
|
||||
<updateMember>(memberSlot, <?hasOffset><memberStorageOffset>,</hasOffset> <memberValues>)
|
||||
</fromCalldata>
|
||||
)");
|
||||
t("fromCalldata", fromCalldata);
|
||||
if (fromCalldata)
|
||||
{
|
||||
t("memberCalldataOffset", suffixedVariableNameList(
|
||||
"memberCalldataOffset_",
|
||||
0,
|
||||
structMembers[i].type->stackItems().size()
|
||||
));
|
||||
t("dynamicallyEncodedMember", structMembers[i].type->isDynamicallyEncoded());
|
||||
if (structMembers[i].type->isDynamicallySized())
|
||||
t("accessCalldataTail", accessCalldataTailFunction(*structMembers[i].type));
|
||||
}
|
||||
t("isValueType", structMembers[i].type->isValueType());
|
||||
t("memberValues", suffixedVariableNameList(
|
||||
"memberValue_",
|
||||
0,
|
||||
structMembers[i].type->stackItems().size()
|
||||
))
|
||||
("hasOffset", structMembers[i].type->isValueType())
|
||||
(
|
||||
));
|
||||
t("hasOffset", structMembers[i].type->isValueType());
|
||||
t(
|
||||
"updateMember",
|
||||
structMembers[i].type->isValueType() ?
|
||||
updateStorageValueFunction(*structMembers[i].type, *structMembers[i].type) :
|
||||
updateStorageValueFunction(*structMembers[i].type, *structMembers[i].type, offset)
|
||||
)
|
||||
("memberStorageSlotDiff", slotDiff.str())
|
||||
("memberStorageOffset", to_string(offset))
|
||||
("memberOffset",
|
||||
updateStorageValueFunction(*structMembers[i].type, *toStructMembers[i].type) :
|
||||
updateStorageValueFunction(*structMembers[i].type, *toStructMembers[i].type, offset)
|
||||
);
|
||||
t("memberStorageSlotDiff", slotDiff.str());
|
||||
t("memberStorageOffset", to_string(offset));
|
||||
t(
|
||||
"memberOffset",
|
||||
fromCalldata ?
|
||||
to_string(fromStructType.calldataOffsetOfMember(structMembers[i].name)) :
|
||||
fromStructType.memoryOffsetOfMember(structMembers[i].name).str()
|
||||
)
|
||||
("loadFromMemoryOrCalldata", readFromMemoryOrCalldata(*structMembers[i].type, fromCalldata))
|
||||
.render();
|
||||
);
|
||||
if (!fromCalldata || structMembers[i].type->isValueType())
|
||||
t("loadFromMemoryOrCalldata", readFromMemoryOrCalldata(*structMembers[i].type, fromCalldata));
|
||||
memberParams[i]["updateMemberCall"] = t.render();
|
||||
}
|
||||
templ("member", memberParams);
|
||||
|
||||
|
@ -181,6 +181,10 @@ public:
|
||||
/// signature: (slot) ->
|
||||
std::string clearStorageArrayFunction(ArrayType const& _type);
|
||||
|
||||
/// @returns the name of a function that will copy array from calldata or memory to storage
|
||||
/// signature (to_slot, from_ptr) ->
|
||||
std::string copyArrayToStorage(ArrayType const& _fromType, ArrayType const& _toType);
|
||||
|
||||
/// Returns the name of a function that will convert a given length to the
|
||||
/// size in memory (number of storage slots or calldata/memory bytes) it
|
||||
/// will require.
|
||||
|
@ -348,18 +348,25 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
|
||||
mappingType ? *mappingType->keyType() : *TypeProvider::uint256()
|
||||
).stackSlots();
|
||||
parameters += keys;
|
||||
code += Whiskers(R"(
|
||||
|
||||
Whiskers templ(R"(
|
||||
<?array>
|
||||
if iszero(lt(<keys>, <length>(slot))) { revert(0, 0) }
|
||||
</array>
|
||||
slot<?array>, offset</array> := <indexAccess>(slot<?+keys>, <keys></+keys>)
|
||||
)")
|
||||
(
|
||||
)");
|
||||
templ(
|
||||
"indexAccess",
|
||||
mappingType ?
|
||||
m_utils.mappingIndexAccessFunction(*mappingType, *mappingType->keyType()) :
|
||||
m_utils.storageArrayIndexAccessFunction(*arrayType)
|
||||
)
|
||||
("array", arrayType != nullptr)
|
||||
("keys", joinHumanReadable(keys))
|
||||
.render();
|
||||
("keys", joinHumanReadable(keys));
|
||||
if (arrayType)
|
||||
templ("length", m_utils.arrayLengthFunction(*arrayType));
|
||||
|
||||
code += templ.render();
|
||||
|
||||
currentType = mappingType ? mappingType->valueType() : arrayType->baseType();
|
||||
}
|
||||
|
@ -387,7 +387,11 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment)
|
||||
|
||||
writeToLValue(*m_currentLValue, value);
|
||||
|
||||
if (m_currentLValue->type.category() != Type::Category::Struct && *_assignment.annotation().type != *TypeProvider::emptyTuple())
|
||||
if (
|
||||
m_currentLValue->type.category() != Type::Category::Struct &&
|
||||
m_currentLValue->type.category() != Type::Category::Array &&
|
||||
*_assignment.annotation().type != *TypeProvider::emptyTuple()
|
||||
)
|
||||
define(_assignment, value);
|
||||
m_currentLValue.reset();
|
||||
|
||||
@ -1763,32 +1767,11 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
auto const& type = dynamic_cast<ArrayType const&>(*_memberAccess.expression().annotation().type);
|
||||
|
||||
if (member == "length")
|
||||
{
|
||||
if (!type.isDynamicallySized())
|
||||
define(_memberAccess) << type.length() << "\n";
|
||||
else
|
||||
switch (type.location())
|
||||
{
|
||||
case DataLocation::CallData:
|
||||
define(_memberAccess, IRVariable(_memberAccess.expression()).part("length"));
|
||||
break;
|
||||
case DataLocation::Storage:
|
||||
{
|
||||
define(_memberAccess) <<
|
||||
m_utils.arrayLengthFunction(type) <<
|
||||
"(" <<
|
||||
IRVariable(_memberAccess.expression()).commaSeparatedList() <<
|
||||
")\n";
|
||||
break;
|
||||
}
|
||||
case DataLocation::Memory:
|
||||
define(_memberAccess) <<
|
||||
"mload(" <<
|
||||
IRVariable(_memberAccess.expression()).commaSeparatedList() <<
|
||||
")\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
define(_memberAccess) <<
|
||||
m_utils.arrayLengthFunction(type) <<
|
||||
"(" <<
|
||||
IRVariable(_memberAccess.expression()).commaSeparatedList() <<
|
||||
")\n";
|
||||
else if (member == "pop" || member == "push")
|
||||
{
|
||||
solAssert(type.location() == DataLocation::Storage, "");
|
||||
|
@ -389,7 +389,6 @@ void BMC::endVisit(FunctionCall const& _funCall)
|
||||
case FunctionType::Kind::ECRecover:
|
||||
case FunctionType::Kind::SHA256:
|
||||
case FunctionType::Kind::RIPEMD160:
|
||||
case FunctionType::Kind::BlockHash:
|
||||
SMTEncoder::endVisit(_funCall);
|
||||
abstractFunctionCall(_funCall);
|
||||
break;
|
||||
@ -409,6 +408,7 @@ void BMC::endVisit(FunctionCall const& _funCall)
|
||||
SMTEncoder::endVisit(_funCall);
|
||||
break;
|
||||
}
|
||||
case FunctionType::Kind::BlockHash:
|
||||
case FunctionType::Kind::AddMod:
|
||||
case FunctionType::Kind::MulMod:
|
||||
[[fallthrough]];
|
||||
|
@ -120,7 +120,7 @@ void CHC::endVisit(ContractDefinition const& _contract)
|
||||
&_contract
|
||||
);
|
||||
addRule(
|
||||
(*implicitConstructorPredicate)({0, state().thisAddress(), state().state()}),
|
||||
(*implicitConstructorPredicate)({0, state().thisAddress(), state().tx(), state().state()}),
|
||||
implicitConstructorPredicate->functor().name
|
||||
);
|
||||
setCurrentBlock(*implicitConstructorPredicate);
|
||||
@ -239,8 +239,9 @@ void CHC::endVisit(FunctionDefinition const& _function)
|
||||
auto ifacePre = smt::interfacePre(*m_interfaces.at(m_currentContract), *m_currentContract, m_context);
|
||||
if (_function.isPublic())
|
||||
{
|
||||
addAssertVerificationTarget(&_function, ifacePre, sum, assertionError);
|
||||
connectBlocks(ifacePre, iface, sum && (assertionError == 0));
|
||||
auto txConstraints = m_context.state().txConstraints(_function);
|
||||
addAssertVerificationTarget(&_function, ifacePre, txConstraints && sum, assertionError);
|
||||
connectBlocks(ifacePre, iface, txConstraints && sum && (assertionError == 0));
|
||||
}
|
||||
}
|
||||
m_currentFunction = nullptr;
|
||||
@ -873,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().state(1)};
|
||||
vector<smtutil::Expression> args{errorFlag().currentValue(), state().thisAddress(), state().tx(), state().state(1)};
|
||||
args += state1 +
|
||||
applyMap(function->parameters(), [this](auto _var) { return valueAtIndex(*_var, 0); }) +
|
||||
vector<smtutil::Expression>{state().state(2)} +
|
||||
@ -1052,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().state()};
|
||||
vector<smtutil::Expression> args{errorFlag().currentValue(), state().thisAddress(), state().tx(), state().state()};
|
||||
|
||||
FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
|
||||
solAssert(funType.kind() == FunctionType::Kind::Internal, "");
|
||||
|
@ -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, preBlockChainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// The signature of a function summary predicate is: summary(error, this, txData, preBlockChainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// Here we are interested in preInputVars.
|
||||
vector<string>::const_iterator first = _args.begin() + 3 + static_cast<int>(stateVars->size());
|
||||
vector<string>::const_iterator first = _args.begin() + 4 + 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,8 +188,8 @@ 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, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// The signature of an implicit constructor summary predicate is: summary(error, this, postBlockchainState, postStateVars).
|
||||
/// 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).
|
||||
/// Here we are interested in postStateVars.
|
||||
|
||||
auto stateVars = stateVariables();
|
||||
@ -199,12 +199,12 @@ vector<string> Predicate::summaryStateValues(vector<string> const& _args) const
|
||||
vector<string>::const_iterator stateLast;
|
||||
if (auto const* function = programFunction())
|
||||
{
|
||||
stateFirst = _args.begin() + 3 + static_cast<int>(stateVars->size()) + static_cast<int>(function->parameters().size()) + 1;
|
||||
stateFirst = _args.begin() + 4 + 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() + 3;
|
||||
stateFirst = _args.begin() + 5;
|
||||
stateLast = stateFirst + static_cast<int>(stateVars->size());
|
||||
}
|
||||
else
|
||||
@ -220,7 +220,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, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// The signature of a function summary predicate is: summary(error, this, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// Here we are interested in postInputVars.
|
||||
auto const* function = programFunction();
|
||||
solAssert(function, "");
|
||||
@ -230,7 +230,7 @@ vector<string> Predicate::summaryPostInputValues(vector<string> const& _args) co
|
||||
|
||||
auto const& inParams = function->parameters();
|
||||
|
||||
vector<string>::const_iterator first = _args.begin() + 3 + static_cast<int>(stateVars->size()) * 2 + static_cast<int>(inParams.size()) + 1;
|
||||
vector<string>::const_iterator first = _args.begin() + 4 + 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 +243,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, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// The signature of a function summary predicate is: summary(error, this, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
|
||||
/// Here we are interested in outputVars.
|
||||
auto const* function = programFunction();
|
||||
solAssert(function, "");
|
||||
@ -253,7 +253,7 @@ vector<string> Predicate::summaryPostOutputValues(vector<string> const& _args) c
|
||||
|
||||
auto const& inParams = function->parameters();
|
||||
|
||||
vector<string>::const_iterator first = _args.begin() + 3 + static_cast<int>(stateVars->size()) * 2 + static_cast<int>(inParams.size()) * 2 + 1;
|
||||
vector<string>::const_iterator first = _args.begin() + 4 + static_cast<int>(stateVars->size()) * 2 + static_cast<int>(inParams.size()) * 2 + 1;
|
||||
|
||||
solAssert(first >= _args.begin() && first <= _args.end(), "");
|
||||
|
||||
|
@ -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.state(0)};
|
||||
vector<smtutil::Expression> stateExprs{state.errorFlag().currentValue(), state.thisAddress(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.state(0), state.state()};
|
||||
vector<smtutil::Expression> stateExprs{state.errorFlag().currentValue(), state.thisAddress(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.state(0)};
|
||||
vector<smtutil::Expression> exprs{_context.state().errorFlag().currentValue(), state.thisAddress(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()};
|
||||
|
@ -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.stateSort()},
|
||||
vector<SortPointer>{_state.errorFlagSort(), _state.thisAddressSort(), _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.stateSort(), _state.stateSort()} + stateSorts(_contract),
|
||||
vector<SortPointer>{_state.errorFlagSort(), _state.thisAddressSort(), _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.stateSort()} +
|
||||
vector<SortPointer>{_state.errorFlagSort(), _state.thisAddressSort(), _state.txSort(), _state.stateSort()} +
|
||||
varSorts +
|
||||
inputSorts +
|
||||
vector<SortPointer>{_state.stateSort()} +
|
||||
|
@ -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, blockchainState).
|
||||
* implicit_constructor(error, this, txData, blockchainState).
|
||||
*
|
||||
* 4. Constructor entry/summary
|
||||
* The summary of an implicit constructor. Signature:
|
||||
* constructor_summary(error, this, blockchainState, blockchainState', stateVariables').
|
||||
* constructor_summary(error, this, txData, blockchainState, blockchainState', stateVariables').
|
||||
*
|
||||
* 5. Function entry/summary
|
||||
* The entry point of a function definition. Signature:
|
||||
* function_entry(error, this, blockchainState, stateVariables, inputVariables, blockchainState', stateVariables', inputVariables', outputVariables').
|
||||
* function_entry(error, this, txData, blockchainState, stateVariables, inputVariables, blockchainState', stateVariables', inputVariables', outputVariables').
|
||||
*
|
||||
* 6. Function body
|
||||
* Use for any predicate within a function. Signature:
|
||||
* function_body(error, this, 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,7 +633,9 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall)
|
||||
case FunctionType::Kind::ECRecover:
|
||||
case FunctionType::Kind::SHA256:
|
||||
case FunctionType::Kind::RIPEMD160:
|
||||
break;
|
||||
case FunctionType::Kind::BlockHash:
|
||||
defineExpr(_funCall, m_context.state().blockhash(expr(*_funCall.arguments().at(0))));
|
||||
break;
|
||||
case FunctionType::Kind::AddMod:
|
||||
case FunctionType::Kind::MulMod:
|
||||
@ -1032,7 +1034,11 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess)
|
||||
if (exprType->category() == Type::Category::Magic)
|
||||
{
|
||||
if (identifier)
|
||||
defineGlobalVariable(identifier->name() + "." + _memberAccess.memberName(), _memberAccess);
|
||||
{
|
||||
auto const& name = identifier->name();
|
||||
solAssert(name == "block" || name == "msg" || name == "tx", "");
|
||||
defineExpr(_memberAccess, m_context.state().txMember(name + "." + _memberAccess.memberName()));
|
||||
}
|
||||
else if (auto magicType = dynamic_cast<MagicType const*>(exprType); magicType->kind() == MagicType::Kind::MetaType)
|
||||
{
|
||||
auto const& memberName = _memberAccess.memberName();
|
||||
|
@ -26,110 +26,126 @@ using namespace solidity;
|
||||
using namespace solidity::smtutil;
|
||||
using namespace solidity::frontend::smt;
|
||||
|
||||
SymbolicState::SymbolicState(EncodingContext& _context):
|
||||
BlockchainVariable::BlockchainVariable(
|
||||
string _name,
|
||||
map<string, smtutil::SortPointer> _members,
|
||||
EncodingContext& _context
|
||||
):
|
||||
m_name(move(_name)),
|
||||
m_members(move(_members)),
|
||||
m_context(_context)
|
||||
{
|
||||
m_stateMembers.emplace("balances", make_shared<smtutil::ArraySort>(smtutil::SortProvider::uintSort, smtutil::SortProvider::uintSort));
|
||||
|
||||
vector<string> members;
|
||||
vector<SortPointer> sorts;
|
||||
for (auto const& [component, sort]: m_stateMembers)
|
||||
for (auto const& [component, sort]: m_members)
|
||||
{
|
||||
members.emplace_back(component);
|
||||
sorts.emplace_back(sort);
|
||||
m_componentIndices[component] = members.size() - 1;
|
||||
}
|
||||
m_stateTuple = make_unique<SymbolicTupleVariable>(
|
||||
make_shared<smtutil::TupleSort>("state_type", members, sorts),
|
||||
"state",
|
||||
m_tuple = make_unique<SymbolicTupleVariable>(
|
||||
make_shared<smtutil::TupleSort>(m_name + "_type", members, sorts),
|
||||
m_name,
|
||||
m_context
|
||||
);
|
||||
}
|
||||
|
||||
smtutil::Expression BlockchainVariable::member(string const& _member) const
|
||||
{
|
||||
return m_tuple->component(m_componentIndices.at(_member));
|
||||
}
|
||||
|
||||
smtutil::Expression BlockchainVariable::assignMember(string const& _member, smtutil::Expression const& _value)
|
||||
{
|
||||
vector<smtutil::Expression> args;
|
||||
for (auto const& m: m_members)
|
||||
if (m.first == _member)
|
||||
args.emplace_back(_value);
|
||||
else
|
||||
args.emplace_back(member(m.first));
|
||||
m_tuple->increaseIndex();
|
||||
auto tuple = m_tuple->currentValue();
|
||||
auto sortExpr = smtutil::Expression(make_shared<smtutil::SortSort>(tuple.sort), tuple.name);
|
||||
m_context.addAssertion(tuple == smtutil::Expression::tuple_constructor(sortExpr, args));
|
||||
return m_tuple->currentValue();
|
||||
}
|
||||
|
||||
void SymbolicState::reset()
|
||||
{
|
||||
m_error.resetIndex();
|
||||
m_thisAddress.resetIndex();
|
||||
m_stateTuple->resetIndex();
|
||||
m_state.reset();
|
||||
m_tx.reset();
|
||||
}
|
||||
|
||||
// Blockchain
|
||||
|
||||
SymbolicIntVariable& SymbolicState::errorFlag()
|
||||
smtutil::Expression SymbolicState::balances() const
|
||||
{
|
||||
return m_error;
|
||||
return m_state.member("balances");
|
||||
}
|
||||
|
||||
SortPointer SymbolicState::errorFlagSort()
|
||||
{
|
||||
return m_error.sort();
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::thisAddress()
|
||||
{
|
||||
return m_thisAddress.currentValue();
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::thisAddress(unsigned _idx)
|
||||
{
|
||||
return m_thisAddress.valueAtIndex(_idx);
|
||||
}
|
||||
|
||||
SortPointer SymbolicState::thisAddressSort()
|
||||
{
|
||||
return m_thisAddress.sort();
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::state()
|
||||
{
|
||||
return m_stateTuple->currentValue();
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::state(unsigned _idx)
|
||||
{
|
||||
return m_stateTuple->valueAtIndex(_idx);
|
||||
}
|
||||
|
||||
SortPointer SymbolicState::stateSort()
|
||||
{
|
||||
return m_stateTuple->sort();
|
||||
}
|
||||
|
||||
void SymbolicState::newState()
|
||||
{
|
||||
m_stateTuple->increaseIndex();
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::balances()
|
||||
{
|
||||
return m_stateTuple->component(m_componentIndices.at("balances"));
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::balance()
|
||||
smtutil::Expression SymbolicState::balance() const
|
||||
{
|
||||
return balance(thisAddress());
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::balance(smtutil::Expression _address)
|
||||
smtutil::Expression SymbolicState::balance(smtutil::Expression _address) const
|
||||
{
|
||||
return smtutil::Expression::select(balances(), move(_address));
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::blockhash(smtutil::Expression _blockNumber) const
|
||||
{
|
||||
return smtutil::Expression::select(m_tx.member("blockhash"), move(_blockNumber));
|
||||
}
|
||||
|
||||
void SymbolicState::transfer(smtutil::Expression _from, smtutil::Expression _to, smtutil::Expression _value)
|
||||
{
|
||||
unsigned indexBefore = m_stateTuple->index();
|
||||
unsigned indexBefore = m_state.index();
|
||||
addBalance(_from, 0 - _value);
|
||||
addBalance(_to, move(_value));
|
||||
unsigned indexAfter = m_stateTuple->index();
|
||||
unsigned indexAfter = m_state.index();
|
||||
solAssert(indexAfter > indexBefore, "");
|
||||
m_stateTuple->increaseIndex();
|
||||
m_state.newVar();
|
||||
/// Do not apply the transfer operation if _from == _to.
|
||||
auto newState = smtutil::Expression::ite(
|
||||
move(_from) == move(_to),
|
||||
m_stateTuple->valueAtIndex(indexBefore),
|
||||
m_stateTuple->valueAtIndex(indexAfter)
|
||||
m_state.value(indexBefore),
|
||||
m_state.value(indexAfter)
|
||||
);
|
||||
m_context.addAssertion(m_stateTuple->currentValue() == newState);
|
||||
m_context.addAssertion(m_state.value() == newState);
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::txMember(string const& _member) const
|
||||
{
|
||||
return m_tx.member(_member);
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::txConstraints(FunctionDefinition const& _function) const
|
||||
{
|
||||
smtutil::Expression conj = smt::symbolicUnknownConstraints(m_tx.member("block.coinbase"), TypeProvider::uint(160)) &&
|
||||
smt::symbolicUnknownConstraints(m_tx.member("msg.sender"), TypeProvider::uint(160)) &&
|
||||
smt::symbolicUnknownConstraints(m_tx.member("tx.origin"), TypeProvider::uint(160));
|
||||
|
||||
if (_function.isPartOfExternalInterface())
|
||||
{
|
||||
auto sig = TypeProvider::function(_function)->externalIdentifier();
|
||||
conj = conj && m_tx.member("msg.sig") == sig;
|
||||
|
||||
auto b0 = sig >> (3 * 8);
|
||||
auto b1 = (sig & 0x00ff0000) >> (2 * 8);
|
||||
auto b2 = (sig & 0x0000ff00) >> (1 * 8);
|
||||
auto b3 = (sig & 0x000000ff);
|
||||
auto data = smtutil::Expression::tuple_get(m_tx.member("msg.data"), 0);
|
||||
conj = conj && smtutil::Expression::select(data, 0) == b0;
|
||||
conj = conj && smtutil::Expression::select(data, 1) == b1;
|
||||
conj = conj && smtutil::Expression::select(data, 2) == b2;
|
||||
conj = conj && smtutil::Expression::select(data, 3) == b3;
|
||||
auto length = smtutil::Expression::tuple_get(m_tx.member("msg.data"), 1);
|
||||
// TODO add ABI size of function input parameters here \/
|
||||
conj = conj && length >= 4;
|
||||
}
|
||||
|
||||
return conj;
|
||||
}
|
||||
|
||||
/// Private helpers.
|
||||
@ -141,20 +157,5 @@ void SymbolicState::addBalance(smtutil::Expression _address, smtutil::Expression
|
||||
_address,
|
||||
balance(_address) + move(_value)
|
||||
);
|
||||
assignStateMember("balances", newBalances);
|
||||
}
|
||||
|
||||
smtutil::Expression SymbolicState::assignStateMember(string const& _member, smtutil::Expression const& _value)
|
||||
{
|
||||
vector<smtutil::Expression> args;
|
||||
for (auto const& member: m_stateMembers)
|
||||
if (member.first == _member)
|
||||
args.emplace_back(_value);
|
||||
else
|
||||
args.emplace_back(m_stateTuple->component(m_componentIndices.at(member.first)));
|
||||
m_stateTuple->increaseIndex();
|
||||
auto tuple = m_stateTuple->currentValue();
|
||||
auto sortExpr = smtutil::Expression(make_shared<smtutil::SortSort>(tuple.sort), tuple.name);
|
||||
m_context.addAssertion(tuple == smtutil::Expression::tuple_constructor(sortExpr, args));
|
||||
return m_stateTuple->currentValue();
|
||||
m_state.assignMember("balances", newBalances);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/formal/SymbolicTypes.h>
|
||||
#include <libsolidity/formal/SymbolicVariables.h>
|
||||
|
||||
#include <libsmtutil/Sorts.h>
|
||||
@ -30,6 +31,31 @@ class EncodingContext;
|
||||
class SymbolicAddressVariable;
|
||||
class SymbolicArrayVariable;
|
||||
|
||||
class BlockchainVariable
|
||||
{
|
||||
public:
|
||||
BlockchainVariable(std::string _name, std::map<std::string, smtutil::SortPointer> _members, EncodingContext& _context);
|
||||
/// @returns the variable data as a tuple.
|
||||
smtutil::Expression value() const { return m_tuple->currentValue(); }
|
||||
smtutil::Expression value(unsigned _idx) const { return m_tuple->valueAtIndex(_idx); }
|
||||
smtutil::SortPointer const& sort() const { return m_tuple->sort(); }
|
||||
unsigned index() const { return m_tuple->index(); }
|
||||
void newVar() { m_tuple->increaseIndex(); }
|
||||
void reset() { m_tuple->resetIndex(); }
|
||||
|
||||
/// @returns the symbolic _member.
|
||||
smtutil::Expression member(std::string const& _member) const;
|
||||
/// Generates a new tuple where _member is assigned _value.
|
||||
smtutil::Expression assignMember(std::string const& _member, smtutil::Expression const& _value);
|
||||
|
||||
private:
|
||||
std::string const m_name;
|
||||
std::map<std::string, smtutil::SortPointer> const m_members;
|
||||
EncodingContext& m_context;
|
||||
std::map<std::string, unsigned> m_componentIndices;
|
||||
std::unique_ptr<SymbolicTupleVariable> m_tuple;
|
||||
};
|
||||
|
||||
/**
|
||||
* Symbolic representation of the blockchain context:
|
||||
* - error flag
|
||||
@ -37,49 +63,75 @@ class SymbolicArrayVariable;
|
||||
* - state, represented as a tuple of:
|
||||
* - balances
|
||||
* - TODO: potentially storage of contracts
|
||||
* - TODO transaction variables
|
||||
* - block and transaction properties, represented as a tuple of:
|
||||
* - blockhash
|
||||
* - block coinbase
|
||||
* - block difficulty
|
||||
* - block gaslimit
|
||||
* - block number
|
||||
* - block timestamp
|
||||
* - TODO gasleft
|
||||
* - msg data
|
||||
* - msg sender
|
||||
* - msg sig
|
||||
* - msg value
|
||||
* - tx gasprice
|
||||
* - tx origin
|
||||
*/
|
||||
class SymbolicState
|
||||
{
|
||||
public:
|
||||
SymbolicState(EncodingContext& _context);
|
||||
SymbolicState(EncodingContext& _context): m_context(_context) {}
|
||||
|
||||
void reset();
|
||||
|
||||
/// Blockchain.
|
||||
/// Error flag.
|
||||
//@{
|
||||
SymbolicIntVariable& errorFlag();
|
||||
smtutil::SortPointer errorFlagSort();
|
||||
SymbolicIntVariable& errorFlag() { return m_error; }
|
||||
smtutil::SortPointer const& errorFlagSort() const { return m_error.sort(); }
|
||||
//@}
|
||||
|
||||
/// This.
|
||||
//@{
|
||||
/// @returns the symbolic value of the currently executing contract's address.
|
||||
smtutil::Expression thisAddress();
|
||||
smtutil::Expression thisAddress(unsigned _idx);
|
||||
smtutil::SortPointer thisAddressSort();
|
||||
|
||||
/// @returns the state as a tuple.
|
||||
smtutil::Expression state();
|
||||
smtutil::Expression state(unsigned _idx);
|
||||
smtutil::SortPointer stateSort();
|
||||
void newState();
|
||||
smtutil::Expression thisAddress() const { return m_thisAddress.currentValue(); }
|
||||
smtutil::Expression thisAddress(unsigned _idx) const { return m_thisAddress.valueAtIndex(_idx); }
|
||||
smtutil::SortPointer const& thisAddressSort() const { return m_thisAddress.sort(); }
|
||||
//@}
|
||||
|
||||
/// Blockchain state.
|
||||
//@{
|
||||
smtutil::Expression state() const { return m_state.value(); }
|
||||
smtutil::Expression state(unsigned _idx) const { return m_state.value(_idx); }
|
||||
smtutil::SortPointer const& stateSort() const { return m_state.sort(); }
|
||||
void newState() { m_state.newVar(); }
|
||||
/// @returns the symbolic balances.
|
||||
smtutil::Expression balances();
|
||||
smtutil::Expression balances() const;
|
||||
/// @returns the symbolic balance of address `this`.
|
||||
smtutil::Expression balance();
|
||||
smtutil::Expression balance() const;
|
||||
/// @returns the symbolic balance of an address.
|
||||
smtutil::Expression balance(smtutil::Expression _address);
|
||||
smtutil::Expression balance(smtutil::Expression _address) const;
|
||||
|
||||
/// Transfer _value from _from to _to.
|
||||
void transfer(smtutil::Expression _from, smtutil::Expression _to, smtutil::Expression _value);
|
||||
//@}
|
||||
|
||||
/// Transaction data.
|
||||
//@{
|
||||
/// @returns the tx data as a tuple.
|
||||
smtutil::Expression tx() const { return m_tx.value(); }
|
||||
smtutil::Expression tx(unsigned _idx) const { return m_tx.value(_idx); }
|
||||
smtutil::SortPointer const& txSort() const { return m_tx.sort(); }
|
||||
void newTx() { m_tx.newVar(); }
|
||||
smtutil::Expression txMember(std::string const& _member) const;
|
||||
smtutil::Expression txConstraints(FunctionDefinition const& _function) const;
|
||||
smtutil::Expression blockhash(smtutil::Expression _blockNumber) const;
|
||||
//@}
|
||||
|
||||
private:
|
||||
/// Adds _value to _account's balance.
|
||||
void addBalance(smtutil::Expression _account, smtutil::Expression _value);
|
||||
|
||||
/// Generates a new tuple where _member is assigned _value.
|
||||
smtutil::Expression assignStateMember(std::string const& _member, smtutil::Expression const& _value);
|
||||
|
||||
EncodingContext& m_context;
|
||||
|
||||
SymbolicIntVariable m_error{
|
||||
@ -94,10 +146,31 @@ private:
|
||||
m_context
|
||||
};
|
||||
|
||||
std::map<std::string, unsigned> m_componentIndices;
|
||||
/// balances, TODO storage of other contracts
|
||||
std::map<std::string, smtutil::SortPointer> m_stateMembers;
|
||||
std::unique_ptr<SymbolicTupleVariable> m_stateTuple;
|
||||
BlockchainVariable m_state{
|
||||
"state",
|
||||
{{"balances", std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::uintSort, smtutil::SortProvider::uintSort)}},
|
||||
m_context
|
||||
};
|
||||
|
||||
BlockchainVariable m_tx{
|
||||
"tx",
|
||||
{
|
||||
{"blockhash", std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::uintSort, smtutil::SortProvider::uintSort)},
|
||||
{"block.coinbase", smt::smtSort(*TypeProvider::address())},
|
||||
{"block.difficulty", smtutil::SortProvider::uintSort},
|
||||
{"block.gaslimit", smtutil::SortProvider::uintSort},
|
||||
{"block.number", smtutil::SortProvider::uintSort},
|
||||
{"block.timestamp", smtutil::SortProvider::uintSort},
|
||||
// TODO gasleft
|
||||
{"msg.data", smt::smtSort(*TypeProvider::bytesMemory())},
|
||||
{"msg.sender", smt::smtSort(*TypeProvider::address())},
|
||||
{"msg.sig", smtutil::SortProvider::uintSort},
|
||||
{"msg.value", smtutil::SortProvider::uintSort},
|
||||
{"tx.gasprice", smtutil::SortProvider::uintSort},
|
||||
{"tx.origin", smt::smtSort(*TypeProvider::address())}
|
||||
},
|
||||
m_context
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#include <libsolidity/formal/SymbolicTypes.h>
|
||||
|
||||
#include <libsolidity/formal/EncodingContext.h>
|
||||
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
#include <libsolidity/ast/Types.h>
|
||||
#include <libsolutil/CommonData.h>
|
||||
@ -535,22 +537,26 @@ void setSymbolicUnknownValue(SymbolicVariable const& _variable, EncodingContext&
|
||||
}
|
||||
|
||||
void setSymbolicUnknownValue(smtutil::Expression _expr, frontend::TypePointer const& _type, EncodingContext& _context)
|
||||
{
|
||||
_context.addAssertion(symbolicUnknownConstraints(_expr, _type));
|
||||
}
|
||||
|
||||
smtutil::Expression symbolicUnknownConstraints(smtutil::Expression _expr, frontend::TypePointer const& _type)
|
||||
{
|
||||
solAssert(_type, "");
|
||||
if (isEnum(*_type))
|
||||
{
|
||||
auto enumType = dynamic_cast<frontend::EnumType const*>(_type);
|
||||
solAssert(enumType, "");
|
||||
_context.addAssertion(_expr >= 0);
|
||||
_context.addAssertion(_expr < enumType->numberOfMembers());
|
||||
return _expr >= 0 && _expr < enumType->numberOfMembers();
|
||||
}
|
||||
else if (isInteger(*_type))
|
||||
{
|
||||
auto intType = dynamic_cast<frontend::IntegerType const*>(_type);
|
||||
solAssert(intType, "");
|
||||
_context.addAssertion(_expr >= minValue(*intType));
|
||||
_context.addAssertion(_expr <= maxValue(*intType));
|
||||
return _expr >= minValue(*intType) && _expr <= maxValue(*intType);
|
||||
}
|
||||
return smtutil::Expression(true);
|
||||
}
|
||||
|
||||
optional<smtutil::Expression> symbolicTypeConversion(TypePointer _from, TypePointer _to)
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/formal/EncodingContext.h>
|
||||
#include <libsolidity/formal/SymbolicVariables.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/Types.h>
|
||||
@ -26,6 +25,8 @@
|
||||
namespace solidity::frontend::smt
|
||||
{
|
||||
|
||||
class EncodingContext;
|
||||
|
||||
/// Returns the SMT sort that models the Solidity type _type.
|
||||
smtutil::SortPointer smtSort(frontend::Type const& _type);
|
||||
std::vector<smtutil::SortPointer> smtSort(std::vector<frontend::TypePointer> const& _types);
|
||||
@ -77,6 +78,7 @@ void setSymbolicZeroValue(SymbolicVariable const& _variable, EncodingContext& _c
|
||||
void setSymbolicZeroValue(smtutil::Expression _expr, frontend::TypePointer const& _type, EncodingContext& _context);
|
||||
void setSymbolicUnknownValue(SymbolicVariable const& _variable, EncodingContext& _context);
|
||||
void setSymbolicUnknownValue(smtutil::Expression _expr, frontend::TypePointer const& _type, EncodingContext& _context);
|
||||
smtutil::Expression symbolicUnknownConstraints(smtutil::Expression _expr, frontend::TypePointer const& _type);
|
||||
|
||||
std::optional<smtutil::Expression> symbolicTypeConversion(TypePointer _from, TypePointer _to);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include <libsolidity/formal/SymbolicVariables.h>
|
||||
|
||||
#include <libsolidity/formal/EncodingContext.h>
|
||||
#include <libsolidity/formal/SymbolicTypes.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
|
||||
|
@ -14,9 +14,9 @@ contract C {
|
||||
}
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 1106800
|
||||
// executionCost: 1147
|
||||
// totalCost: 1107947
|
||||
// codeDepositCost: 1107400
|
||||
// executionCost: 1154
|
||||
// totalCost: 1108554
|
||||
// external:
|
||||
// a(): 1130
|
||||
// b(uint256): infinite
|
||||
|
@ -17,9 +17,9 @@ contract C {
|
||||
// optimize-yul: true
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 604400
|
||||
// codeDepositCost: 605000
|
||||
// executionCost: 638
|
||||
// totalCost: 605038
|
||||
// totalCost: 605638
|
||||
// external:
|
||||
// a(): 1029
|
||||
// b(uint256): 2084
|
||||
|
@ -24,9 +24,9 @@ contract Large {
|
||||
}
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 637000
|
||||
// codeDepositCost: 637600
|
||||
// executionCost: 670
|
||||
// totalCost: 637670
|
||||
// totalCost: 638270
|
||||
// external:
|
||||
// a(): 1051
|
||||
// b(uint256): 2046
|
||||
|
@ -27,9 +27,9 @@ contract Large {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 260600
|
||||
// codeDepositCost: 261200
|
||||
// executionCost: 300
|
||||
// totalCost: 260900
|
||||
// totalCost: 261500
|
||||
// external:
|
||||
// a(): 998
|
||||
// b(uint256): 2305
|
||||
|
@ -11,9 +11,9 @@ contract Medium {
|
||||
}
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 253200
|
||||
// codeDepositCost: 253800
|
||||
// executionCost: 294
|
||||
// totalCost: 253494
|
||||
// totalCost: 254094
|
||||
// external:
|
||||
// a(): 1028
|
||||
// b(uint256): 2046
|
||||
|
@ -14,9 +14,9 @@ contract Medium {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 141000
|
||||
// codeDepositCost: 141600
|
||||
// executionCost: 190
|
||||
// totalCost: 141190
|
||||
// totalCost: 141790
|
||||
// external:
|
||||
// a(): 998
|
||||
// b(uint256): 2063
|
||||
|
@ -6,9 +6,9 @@ contract Small {
|
||||
}
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 84800
|
||||
// codeDepositCost: 85400
|
||||
// executionCost: 135
|
||||
// totalCost: 84935
|
||||
// totalCost: 85535
|
||||
// external:
|
||||
// fallback: 129
|
||||
// a(): 983
|
||||
|
@ -9,9 +9,9 @@ contract Small {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 60600
|
||||
// codeDepositCost: 61200
|
||||
// executionCost: 111
|
||||
// totalCost: 60711
|
||||
// totalCost: 61311
|
||||
// external:
|
||||
// fallback: 118
|
||||
// a(): 976
|
||||
|
@ -15,7 +15,8 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// EVMVersion: >homestead
|
||||
// ----
|
||||
// h(uint256[2][]) : 0x20, 3, 123, 124, 223, 224, 323, 324 -> 32, 256, 0x20, 3, 123, 124, 223, 224, 323, 324
|
||||
// h(uint256[2][]): 0x20, 3, 123, 124, 223, 224, 323, 324 -> 32, 256, 0x20, 3, 123, 124, 223, 224, 323, 324
|
||||
// i(uint256[2][2]): 123, 124, 223, 224 -> 32, 128, 123, 124, 223, 224
|
||||
|
@ -19,5 +19,7 @@ contract C {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> true
|
||||
|
@ -44,5 +44,7 @@ contract C {
|
||||
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> true
|
||||
|
@ -1,11 +0,0 @@
|
||||
contract C {
|
||||
uint[] a;
|
||||
function f() public returns (uint, uint) {
|
||||
uint[] memory b = new uint[](3);
|
||||
b[0] = 1;
|
||||
a = b;
|
||||
return (a[0], a.length);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f() -> 1, 3
|
@ -10,6 +10,8 @@ contract Test {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// set(uint24[3][]): 0x20, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12 -> 0x06
|
||||
// data(uint256,uint256): 0x02, 0x02 -> 0x09
|
||||
|
@ -14,6 +14,5 @@ contract c {
|
||||
uint8(data[97]) == 97;
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// test1() -> true
|
||||
|
@ -10,7 +10,6 @@ contract c {
|
||||
|
||||
bytes data;
|
||||
}
|
||||
|
||||
// ----
|
||||
// getLength() -> 0
|
||||
// set(): 1, 2 -> true
|
||||
|
@ -7,6 +7,8 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(): 1, 2, 3 ->
|
||||
// a(uint256): 0 -> 1
|
||||
|
@ -0,0 +1,17 @@
|
||||
contract C {
|
||||
uint256[] x;
|
||||
function f() public returns(uint256) {
|
||||
x.push(42); x.push(42); x.push(42); x.push(42);
|
||||
uint256[] memory y = new uint256[](1);
|
||||
y[0] = 23;
|
||||
x = y;
|
||||
assembly { sstore(x.slot, 4) }
|
||||
assert(x[1] == 0);
|
||||
assert(x[2] == 0);
|
||||
return x[3];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 0
|
@ -0,0 +1,46 @@
|
||||
contract C {
|
||||
uint128[] x;
|
||||
uint64[] x1;
|
||||
uint120[] x2;
|
||||
function f() public returns(uint128) {
|
||||
x.push(42); x.push(42); x.push(42); x.push(42);
|
||||
uint128[] memory y = new uint128[](1);
|
||||
y[0] = 23;
|
||||
x = y;
|
||||
assembly { sstore(x.slot, 4) }
|
||||
assert(x[0] == 23);
|
||||
assert(x[2] == 0);
|
||||
assert(x[3] == 0);
|
||||
return x[1];
|
||||
}
|
||||
|
||||
function g() public returns(uint64) {
|
||||
x1.push(42); x1.push(42); x1.push(42); x1.push(42);
|
||||
uint64[] memory y = new uint64[](1);
|
||||
y[0] = 23;
|
||||
x1 = y;
|
||||
assembly { sstore(x1.slot, 4) }
|
||||
assert(x1[0] == 23);
|
||||
assert(x1[2] == 0);
|
||||
assert(x1[3] == 0);
|
||||
return x1[1];
|
||||
}
|
||||
|
||||
function h() public returns(uint120) {
|
||||
x2.push(42); x2.push(42); x2.push(42); x2.push(42);
|
||||
uint120[] memory y = new uint120[](1);
|
||||
y[0] = 23;
|
||||
x2 = y;
|
||||
assembly { sstore(x2.slot, 4) }
|
||||
assert(x2[0] == 23);
|
||||
assert(x2[2] == 0);
|
||||
assert(x2[3] == 0);
|
||||
return x2[1];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> 0
|
||||
// g() -> 0
|
||||
// h() -> 0
|
@ -0,0 +1,30 @@
|
||||
contract C {
|
||||
uint128[13] unused;
|
||||
uint32[] a;
|
||||
uint32[3] b;
|
||||
function f() public returns (uint32, uint256) {
|
||||
uint32[] memory m = new uint32[](3);
|
||||
m[0] = 1;
|
||||
m[1] = 2;
|
||||
m[2] = 3;
|
||||
a = m;
|
||||
assert(a[0] == m[0]);
|
||||
assert(a[1] == m[1]);
|
||||
assert(a[2] == m[2]);
|
||||
return (a[0], a.length);
|
||||
}
|
||||
function g() public returns (uint32, uint32, uint32) {
|
||||
uint32[3] memory m;
|
||||
m[0] = 1; m[1] = 2; m[2] = 3;
|
||||
a = m;
|
||||
b = m;
|
||||
assert(a[0] == b[0] && a[1] == b[1] && a[2] == b[2]);
|
||||
assert(a.length == b.length);
|
||||
return (a[0], b[1], a[2]);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 1, 3
|
||||
// g() -> 1, 2, 3
|
@ -0,0 +1,16 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract c {
|
||||
uint256[][] a;
|
||||
|
||||
function test(uint256[][] calldata d) external returns (uint256, uint256) {
|
||||
a = d;
|
||||
assert(a[0][0] == d[0][0]);
|
||||
assert(a[0][1] == d[0][1]);
|
||||
return (a.length, a[1][0] + a[1][1]);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// test(uint256[][]): 0x20, 2, 0x40, 0x40, 2, 23, 42 -> 2, 65
|
@ -0,0 +1,45 @@
|
||||
contract Test {
|
||||
uint128[13] unused;
|
||||
uint256[][] a;
|
||||
uint256[4][] b;
|
||||
uint256[2][3] c;
|
||||
|
||||
function test() external returns (uint256) {
|
||||
uint256[][] memory m = new uint256[][](2);
|
||||
m[0] = new uint256[](3);
|
||||
m[0][0] = 7; m[0][1] = 8; m[0][2] = 9;
|
||||
m[1] = new uint256[](4);
|
||||
m[1][1] = 7; m[1][2] = 8; m[1][3] = 9;
|
||||
a = m;
|
||||
return a[0][0] + a[0][1] + a[1][3];
|
||||
}
|
||||
|
||||
function test1() external returns (uint256) {
|
||||
uint256[2][] memory m = new uint256[2][](1);
|
||||
m[0][0] = 1; m[0][1] = 2;
|
||||
b = m;
|
||||
return b[0][0] + b[0][1];
|
||||
}
|
||||
|
||||
function test2() external returns (uint256) {
|
||||
uint256[2][2] memory m;
|
||||
m[0][0] = 1; m[1][1] = 2; m[0][1] = 3;
|
||||
c = m;
|
||||
return c[0][0] + c[1][1] + c[0][1];
|
||||
}
|
||||
|
||||
function test3() external returns (uint256) {
|
||||
uint256[2][3] memory m;
|
||||
m[0][0] = 7; m[1][0] = 8; m[2][0] = 9;
|
||||
m[0][1] = 7; m[1][1] = 8; m[2][1] = 9;
|
||||
a = m;
|
||||
return a[0][0] + a[1][0] + a[2][1];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> 24
|
||||
// test1() -> 3
|
||||
// test2() -> 6
|
||||
// test3() -> 24
|
@ -0,0 +1,19 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract C {
|
||||
struct S {
|
||||
uint128 a;
|
||||
uint64 b;
|
||||
uint128 c;
|
||||
}
|
||||
uint128[137] unused;
|
||||
S[] s;
|
||||
function f(S[] calldata c) public returns (uint128, uint64, uint128) {
|
||||
s = c;
|
||||
return (s[2].a, s[1].b, s[0].c);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f((uint128, uint64, uint128)[]): 0x20, 3, 0, 0, 12, 0, 11, 0, 10, 0, 0 -> 10, 11, 12
|
@ -0,0 +1,21 @@
|
||||
contract C {
|
||||
struct S {
|
||||
uint128 a;
|
||||
uint64 b;
|
||||
uint128 c;
|
||||
}
|
||||
uint128[137] unused;
|
||||
S[] s;
|
||||
function f() public returns (uint128, uint64, uint128) {
|
||||
S[] memory m = new S[](3);
|
||||
m[2].a = 10;
|
||||
m[1].b = 11;
|
||||
m[0].c = 12;
|
||||
s = m;
|
||||
return (s[2].a, s[1].b, s[0].c);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> 10, 11, 12
|
@ -0,0 +1,18 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract C {
|
||||
struct S {
|
||||
uint256[] a;
|
||||
}
|
||||
|
||||
S[] s;
|
||||
|
||||
function f(S[] calldata c) external returns (uint256, uint256) {
|
||||
s = c;
|
||||
return (s[1].a.length, s[1].a[0]);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f((uint256[])[]): 0x20, 3, 0x60, 0x60, 0x60, 0x20, 3, 1, 2, 3 -> 3, 1
|
@ -0,0 +1,28 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract C {
|
||||
struct S {
|
||||
uint136 p;
|
||||
uint128[3] b;
|
||||
uint128[] c;
|
||||
}
|
||||
|
||||
S[] s;
|
||||
|
||||
function f() external returns (uint256, uint256, uint128, uint128) {
|
||||
S[] memory m = new S[](3);
|
||||
m[1] = S(0, [uint128(1), 2, 3], new uint128[](3));
|
||||
m[1].c[0] = 1;
|
||||
m[1].c[1] = 2;
|
||||
m[1].c[2] = 3;
|
||||
s = m;
|
||||
assert(s.length == m.length);
|
||||
assert(s[1].b[1] == m[1].b[1]);
|
||||
assert(s[1].c[0] == m[1].c[0]);
|
||||
return (s[1].b.length, s[1].c.length, s[1].b[2], s[1].c[0]);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: true
|
||||
// ----
|
||||
// f() -> 3, 3, 3, 1
|
@ -0,0 +1,13 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract C {
|
||||
uint256[] s;
|
||||
function f(uint256[] calldata data) external returns (uint) {
|
||||
s = data;
|
||||
return s[0];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256[]): 0x20, 0x03, 0x1, 0x2, 0x3 -> 0x1
|
@ -11,6 +11,8 @@ contract C {
|
||||
return uint256(uint8(data[0][4]));
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bytes32): "789" -> "9"
|
||||
// g(bytes32): "789" -> 0x35
|
||||
|
@ -11,5 +11,7 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 1, 2, 3, 4, 5
|
||||
|
@ -8,6 +8,8 @@ contract C {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// constructor(): 1, 2, 3, 4 ->
|
||||
// a() -> 1
|
||||
|
@ -22,6 +22,8 @@ contract test {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(bool): true -> 1
|
||||
// f(bool): false -> 2
|
||||
|
@ -0,0 +1,21 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
library Lib {
|
||||
struct Items {
|
||||
mapping (uint => uint) a;
|
||||
}
|
||||
|
||||
function get() public returns (Items storage x) {
|
||||
assembly { x.slot := 123 }
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f() public returns(uint256 slot) {
|
||||
Lib.Items storage ptr = Lib.get();
|
||||
assembly { slot := ptr.slot }
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// library: Lib
|
||||
// f() -> 123
|
@ -22,6 +22,8 @@ contract test {
|
||||
multiple_map[2][1][2].finalArray[3] = 5;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// data(uint256): 0 -> 8
|
||||
// data(uint256): 8 -> FAILURE
|
||||
|
@ -19,6 +19,8 @@ contract Test {
|
||||
return z;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// x(uint256): 0 -> -1
|
||||
// x(uint256): 1 -> -2
|
||||
|
@ -26,5 +26,7 @@ contract C {
|
||||
x2 = s.s3.x2;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// get() -> 0x01, 0x00, 0x09, 0x00, 0x04, 0x05
|
||||
|
@ -8,7 +8,6 @@ contract C {
|
||||
|
||||
bytes savedData;
|
||||
}
|
||||
|
||||
// ----
|
||||
// save() -> 24 # empty copy loop #
|
||||
// save(): "abcdefg" -> 24
|
||||
|
@ -14,10 +14,10 @@ contract C {
|
||||
// Safe but knowledge about `c` is erased because `b` could be pointing to `c[x][y]`.
|
||||
assert(c[0][0][0] == 12);
|
||||
// Safe but knowledge about `d` is erased because `b` could be pointing to `d`.
|
||||
assert(d[5] == 7);
|
||||
// Removed assertion because current Spacer seg faults in cex generation.
|
||||
//assert(d[5] == 7);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (193-217): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (309-333): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (419-436): CHC: Assertion violation happens here.
|
||||
|
@ -13,8 +13,8 @@ contract C {
|
||||
// If only looking at `f`, it looks like this.balance always decreases.
|
||||
// However, the edge case of a contract `selfdestruct` sending its remaining balance
|
||||
// to this contract should make the claim false (since there's no fallback/receive here).
|
||||
assert(address(this).balance == t);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(address(this).balance == t);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (496-530): CHC: Assertion violation happens here.
|
||||
|
@ -20,9 +20,10 @@ contract C {
|
||||
|
||||
function f() public {
|
||||
uint oldX = x;
|
||||
d.d();
|
||||
// Removed because Spacer 4.8.9 seg faults.
|
||||
//d.d();
|
||||
assert(oldX == x);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (286-303): CHC: Assertion violation happens here.
|
||||
// Warning 2018: (236-355): Function state mutability can be restricted to view
|
||||
|
@ -1,24 +0,0 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
uint y;
|
||||
function c(uint _y) public returns (uint) {
|
||||
y = _y;
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
contract B is C {
|
||||
function b() public returns (uint) { return c(42); }
|
||||
}
|
||||
|
||||
contract A is B {
|
||||
uint public x;
|
||||
|
||||
function a() public {
|
||||
x = b();
|
||||
assert(x < 40);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (274-288): CHC: Assertion violation happens here.
|
@ -13,3 +13,4 @@ contract Simple {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 4661: (187-201): BMC: Assertion violation happens here.
|
||||
|
@ -25,10 +25,10 @@ contract C {
|
||||
|
||||
// Fails due to j.
|
||||
function i() public view {
|
||||
assert(x < 2);
|
||||
// Disabled because Spacer 4.8.9 seg faults.
|
||||
//assert(x < 2);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTSolvers: z3
|
||||
// ----
|
||||
// Warning 6328: (311-324): CHC: Assertion violation happens here.
|
||||
|
@ -9,12 +9,12 @@ contract LoopFor2 {
|
||||
b[i] = i + 1;
|
||||
c[i] = b[i];
|
||||
}
|
||||
assert(b[0] == c[0]);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(b[0] == c[0]);
|
||||
assert(a[0] == 900);
|
||||
assert(b[0] == 900);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (281-301): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (305-324): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (328-347): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (373-392): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (396-415): CHC: Assertion violation happens here.
|
||||
|
@ -11,13 +11,12 @@ contract LoopFor2 {
|
||||
b[i] = i + 1;
|
||||
c[i] = b[i];
|
||||
}
|
||||
assert(b[0] == c[0]);
|
||||
assert(a[0] == 900);
|
||||
assert(b[0] == 900);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(b[0] == c[0]);
|
||||
//assert(a[0] == 900);
|
||||
//assert(b[0] == 900);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTSolvers: z3
|
||||
// ----
|
||||
// Warning 6328: (274-294): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (321-340): CHC: Assertion violation happens here.
|
||||
|
@ -11,7 +11,8 @@ contract LoopFor2 {
|
||||
c[i] = b[i];
|
||||
++i;
|
||||
}
|
||||
assert(b[0] == c[0]);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(b[0] == c[0]);
|
||||
assert(a[0] == 900);
|
||||
assert(b[0] == 900);
|
||||
}
|
||||
@ -19,6 +20,5 @@ contract LoopFor2 {
|
||||
// ====
|
||||
// SMTSolvers: z3
|
||||
// ----
|
||||
// Warning 6328: (281-301): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (305-324): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (328-347): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (373-392): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (396-415): CHC: Assertion violation happens here.
|
||||
|
@ -15,13 +15,13 @@ contract LoopFor2 {
|
||||
}
|
||||
// Fails due to aliasing, since both b and c are
|
||||
// memory references of same type.
|
||||
assert(b[0] == c[0]);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(b[0] == c[0]);
|
||||
assert(a[0] == 900);
|
||||
assert(b[0] == 900);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(b[0] == 900);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTSolvers: z3
|
||||
// ----
|
||||
// Warning 6328: (362-382): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (409-428): CHC: Assertion violation happens here.
|
||||
|
@ -34,5 +34,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (516-534): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (573-587): CHC: Assertion violation happens here.
|
||||
|
@ -13,9 +13,9 @@ contract C {
|
||||
d.d();
|
||||
return x;
|
||||
}
|
||||
function f(bool b) public {
|
||||
function f() public {
|
||||
x = 1;
|
||||
uint y = b ? g() : 3;
|
||||
uint y = g();
|
||||
assert(x == 2 || x == 1);
|
||||
}
|
||||
function h() public {
|
||||
@ -23,5 +23,5 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 2072: (288-294): Unused local variable.
|
||||
// Warning 6328: (318-342): CHC: Assertion violation happens here.
|
||||
// Warning 2072: (282-288): Unused local variable.
|
||||
// Warning 6328: (304-328): CHC: Assertion violation happens here.
|
||||
|
@ -17,7 +17,8 @@ contract C {
|
||||
b[x][y] = v;
|
||||
delete b[x];
|
||||
// Not necessarily the case.
|
||||
assert(b[y][x] == 0);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(b[y][x] == 0);
|
||||
}
|
||||
function i(uint x, uint y, uint v) public {
|
||||
b[x][y] = v;
|
||||
@ -38,5 +39,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (372-392): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (617-637): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (685-705): CHC: Assertion violation happens here.
|
||||
|
@ -12,4 +12,3 @@ contract C
|
||||
// ----
|
||||
// Warning 6328: (85-109): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (113-137): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (155-191): CHC: Assertion violation happens here.
|
||||
|
@ -4,7 +4,23 @@ contract C
|
||||
{
|
||||
function f() public payable {
|
||||
assert(msg.data.length > 0);
|
||||
// Fails since calldata size should be 4
|
||||
assert(msg.data.length > 4);
|
||||
// f's sig is 0x26121ff0
|
||||
assert(msg.data[0] == 0x26);
|
||||
assert(msg.data[1] == 0x12);
|
||||
assert(msg.data[2] == 0x1f);
|
||||
assert(msg.data[3] == 0xf0);
|
||||
}
|
||||
function g() public payable {
|
||||
// g's sig is 0xe2179b8e
|
||||
assert(msg.data[0] == 0xe2);
|
||||
assert(msg.data[1] == 0x17);
|
||||
assert(msg.data[2] == 0x9b);
|
||||
// Fails
|
||||
assert(msg.data[3] == 0x8f);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (79-106): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (153-180): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (500-527): CHC: Assertion violation happens here.
|
||||
|
@ -2,9 +2,29 @@ pragma experimental SMTChecker;
|
||||
|
||||
contract C
|
||||
{
|
||||
function f() public payable {
|
||||
function f() public pure {
|
||||
assert(msg.sig == 0x00000000);
|
||||
assert(msg.sig == 0x26121ff0);
|
||||
fi();
|
||||
gi();
|
||||
}
|
||||
function fi() internal pure {
|
||||
assert(msg.sig == 0x26121ff0);
|
||||
}
|
||||
function g() public pure {
|
||||
assert(msg.sig == 0xe2179b8e);
|
||||
gi();
|
||||
}
|
||||
function gi() internal pure {
|
||||
// Fails since f can also call gi in which case msg.sig == 0x26121ff0
|
||||
assert(msg.sig == 0xe2179b8e);
|
||||
}
|
||||
function h() public pure {
|
||||
// Fails since gi can also call h in which case msg.sig can be f() or g()
|
||||
assert(msg.sig == 0xe2179b8e);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (79-108): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (76-105): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (403-432): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (543-572): CHC: Assertion violation happens here.
|
||||
|
@ -0,0 +1,21 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
uint gleft;
|
||||
|
||||
function f() public payable {
|
||||
gleft = gasleft();
|
||||
|
||||
fi();
|
||||
|
||||
assert(gleft == gasleft());
|
||||
assert(gleft >= gasleft());
|
||||
}
|
||||
|
||||
function fi() internal view {
|
||||
assert(gleft == gasleft());
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (124-150): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (219-245): CHC: Assertion violation happens here.
|
@ -0,0 +1,61 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
bytes32 bhash;
|
||||
address coin;
|
||||
uint dif;
|
||||
uint glimit;
|
||||
uint number;
|
||||
uint tstamp;
|
||||
bytes mdata;
|
||||
address sender;
|
||||
bytes4 sig;
|
||||
uint value;
|
||||
uint gprice;
|
||||
address origin;
|
||||
|
||||
function f() public payable {
|
||||
bhash = blockhash(12);
|
||||
coin = block.coinbase;
|
||||
dif = block.difficulty;
|
||||
glimit = block.gaslimit;
|
||||
number = block.number;
|
||||
tstamp = block.timestamp;
|
||||
mdata = msg.data;
|
||||
sender = msg.sender;
|
||||
sig = msg.sig;
|
||||
value = msg.value;
|
||||
gprice = tx.gasprice;
|
||||
origin = tx.origin;
|
||||
|
||||
fi();
|
||||
|
||||
assert(bhash == blockhash(12));
|
||||
assert(coin == block.coinbase);
|
||||
assert(dif == block.difficulty);
|
||||
assert(glimit == block.gaslimit);
|
||||
assert(number == block.number);
|
||||
assert(tstamp == block.timestamp);
|
||||
assert(mdata.length == msg.data.length);
|
||||
assert(sender == msg.sender);
|
||||
assert(sig == msg.sig);
|
||||
assert(value == msg.value);
|
||||
assert(gprice == tx.gasprice);
|
||||
assert(origin == tx.origin);
|
||||
}
|
||||
|
||||
function fi() internal view {
|
||||
assert(bhash == blockhash(12));
|
||||
assert(coin == block.coinbase);
|
||||
assert(dif == block.difficulty);
|
||||
assert(glimit == block.gaslimit);
|
||||
assert(number == block.number);
|
||||
assert(tstamp == block.timestamp);
|
||||
assert(mdata.length == msg.data.length);
|
||||
assert(sender == msg.sender);
|
||||
assert(sig == msg.sig);
|
||||
assert(value == msg.value);
|
||||
assert(gprice == tx.gasprice);
|
||||
assert(origin == tx.origin);
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
contract C {
|
||||
bytes32 bhash;
|
||||
address coin;
|
||||
uint dif;
|
||||
uint glimit;
|
||||
uint number;
|
||||
uint tstamp;
|
||||
bytes mdata;
|
||||
address sender;
|
||||
bytes4 sig;
|
||||
uint value;
|
||||
uint gprice;
|
||||
address origin;
|
||||
|
||||
function f() public payable {
|
||||
bhash = blockhash(12);
|
||||
coin = block.coinbase;
|
||||
dif = block.difficulty;
|
||||
glimit = block.gaslimit;
|
||||
number = block.number;
|
||||
tstamp = block.timestamp;
|
||||
mdata = msg.data;
|
||||
sender = msg.sender;
|
||||
sig = msg.sig;
|
||||
value = msg.value;
|
||||
gprice = tx.gasprice;
|
||||
origin = tx.origin;
|
||||
|
||||
fi();
|
||||
|
||||
assert(bhash == blockhash(122));
|
||||
assert(coin != block.coinbase);
|
||||
assert(dif != block.difficulty);
|
||||
assert(glimit != block.gaslimit);
|
||||
assert(number != block.number);
|
||||
assert(tstamp != block.timestamp);
|
||||
assert(mdata.length != msg.data.length);
|
||||
assert(sender != msg.sender);
|
||||
assert(sig != msg.sig);
|
||||
assert(value != msg.value);
|
||||
assert(gprice != tx.gasprice);
|
||||
assert(origin != tx.origin);
|
||||
}
|
||||
|
||||
function fi() internal view {
|
||||
assert(bhash == blockhash(122));
|
||||
assert(coin != block.coinbase);
|
||||
assert(dif != block.difficulty);
|
||||
assert(glimit != block.gaslimit);
|
||||
assert(number != block.number);
|
||||
assert(tstamp != block.timestamp);
|
||||
assert(mdata.length != msg.data.length);
|
||||
assert(sender != msg.sender);
|
||||
assert(sig != msg.sig);
|
||||
assert(value != msg.value);
|
||||
assert(gprice != tx.gasprice);
|
||||
assert(origin != tx.origin);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (545-576): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (580-610): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (614-645): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (649-681): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (685-715): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (719-752): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (756-795): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (799-827): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (831-853): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (857-883): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (887-916): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (920-947): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (986-1017): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1021-1051): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1055-1086): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1090-1122): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1126-1156): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1160-1193): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1197-1236): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1240-1268): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1272-1294): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1298-1324): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1328-1357): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1361-1388): CHC: Assertion violation happens here.
|
@ -16,7 +16,8 @@ contract C
|
||||
// erase knowledge about storage references.
|
||||
assert(c[0] == 42);
|
||||
assert(a[0] == 2);
|
||||
assert(b[0] == 1);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(b[0] == 1);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
|
@ -17,7 +17,8 @@ contract C
|
||||
// erase knowledge about memory references.
|
||||
assert(c[0] == 42);
|
||||
// Fails because d == a is possible.
|
||||
assert(d[0] == 42);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(d[0] == 42);
|
||||
// Fails because b == a and d == a are possible.
|
||||
assert(a[0] == 2);
|
||||
// b == a is possible, but does not fail because b
|
||||
@ -26,5 +27,4 @@ contract C
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (431-449): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (504-521): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (572-589): CHC: Assertion violation happens here.
|
||||
|
@ -16,7 +16,8 @@ contract C
|
||||
// Should not fail since knowledge is erased only for mapping (uint => uint).
|
||||
assert(severalMaps8[0][0] == 42);
|
||||
// Should fail since map == severalMaps3d[0][0] is possible.
|
||||
assert(severalMaps3d[0][0][0] == 42);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(severalMaps3d[0][0][0] == 42);
|
||||
}
|
||||
function g(uint x) public {
|
||||
f(severalMaps[x]);
|
||||
@ -24,4 +25,3 @@ contract C
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (421-452): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (635-671): CHC: Assertion violation happens here.
|
||||
|
@ -7,12 +7,12 @@ contract C
|
||||
require(a[0] == 2);
|
||||
b[0] = 1;
|
||||
// Should fail since b == c is possible.
|
||||
assert(c[0] == 42);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(c[0] == 42);
|
||||
// Should fail since b == a is possible.
|
||||
assert(a[0] == 2);
|
||||
assert(b[0] == 1);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (228-246): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (293-310): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (361-378): CHC: Assertion violation happens here.
|
||||
|
@ -16,7 +16,8 @@ contract C
|
||||
// Should not fail since knowledge is erased only for mapping (uint => uint).
|
||||
assert(severalMaps8[0][0] == 42);
|
||||
// Should fail since map == severalMaps3d[0][0] is possible.
|
||||
assert(severalMaps3d[0][0][0] == 42);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(severalMaps3d[0][0][0] == 42);
|
||||
}
|
||||
function g(uint x) public {
|
||||
f(severalMaps[x]);
|
||||
@ -24,4 +25,3 @@ contract C
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (425-456): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (639-675): CHC: Assertion violation happens here.
|
||||
|
@ -16,7 +16,8 @@ contract C
|
||||
// Fails because map2 == a is possible.
|
||||
assert(a[0] == 42);
|
||||
// Fails because map2 == maps[0] is possible.
|
||||
assert(maps[0][0] == 42);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(maps[0][0] == 42);
|
||||
// Should not fail since knowledge is erased only for mapping (uint => uint).
|
||||
assert(maps8[0][0] == 42);
|
||||
assert(map2[0] == 1);
|
||||
@ -32,4 +33,3 @@ contract C
|
||||
// ----
|
||||
// Warning 6328: (397-417): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (463-481): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (533-557): CHC: Assertion violation happens here.
|
||||
|
@ -14,19 +14,21 @@ contract C {
|
||||
}
|
||||
function f(S memory s2) public pure {
|
||||
S[] memory s1 = new S[](3);
|
||||
assert(s1.length == 3);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(s1.length == 3);
|
||||
s1[0].x = 2;
|
||||
assert(s1[0].x == s2.x);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(s1[0].x == s2.x);
|
||||
s1[1].t.y = 3;
|
||||
assert(s1[1].t.y == s2.t.y);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(s1[1].t.y == s2.t.y);
|
||||
s1[2].a[2] = 4;
|
||||
assert(s1[2].a[2] == s2.a[2]);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(s1[2].a[2] == s2.a[2]);
|
||||
s1[0].ts[3].y = 5;
|
||||
assert(s1[0].ts[3].y == s2.ts[3].y);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(s1[0].ts[3].y == s2.ts[3].y);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (283-306): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (327-354): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (376-405): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (430-465): CHC: Assertion violation happens here.
|
||||
// Warning 5667: (183-194): Unused function parameter. Remove or comment out the variable name to silence this warning.
|
||||
|
@ -9,8 +9,9 @@ contract C {
|
||||
S s2;
|
||||
function f(bool b) public {
|
||||
S storage s3 = b ? s1 : s2;
|
||||
assert(s3.x == s1.x);
|
||||
assert(s3.x == s2.x);
|
||||
// Disabled because Spacer 4.8.9 seg fauts.
|
||||
//assert(s3.x == s1.x);
|
||||
//assert(s3.x == s2.x);
|
||||
// This is safe.
|
||||
assert(s3.x == s1.x || s3.x == s2.x);
|
||||
// This fails as false positive because of lack of support to aliasing.
|
||||
@ -25,6 +26,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (158-178): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (182-202): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (352-388): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (402-438): CHC: Assertion violation happens here.
|
||||
|
@ -15,20 +15,20 @@ contract C {
|
||||
function f(S memory s2) public pure {
|
||||
S memory s1;
|
||||
s1.x = 2;
|
||||
assert(s1.x == s2.x);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(s1.x == s2.x);
|
||||
s1.t.y = 3;
|
||||
assert(s1.t.y == s2.t.y);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(s1.t.y == s2.t.y);
|
||||
s1.a[2] = 4;
|
||||
assert(s1.a[2] == s2.a[2]);
|
||||
s1.ts[3].y = 5;
|
||||
assert(s1.ts[3].y == s2.ts[3].y);
|
||||
// Removed because current Spacer seg faults in cex generation.
|
||||
//assert(s1.ts[3].y == s2.ts[3].y);
|
||||
s1.ts[4].a[5] = 6;
|
||||
assert(s1.ts[4].a[5] == s2.ts[4].a[5]);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (239-259): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (277-301): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (320-346): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (368-400): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (425-463): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (456-482): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (629-667): CHC: Assertion violation happens here.
|
||||
|
@ -8,11 +8,11 @@ contract C {
|
||||
S s1;
|
||||
S s2;
|
||||
function f() public view {
|
||||
assert(s1.m[0] == s2.m[0]);
|
||||
// Disabled because Spacer 4.8.9 seg faults.
|
||||
//assert(s1.m[0] == s2.m[0]);
|
||||
}
|
||||
function g(uint a, uint b) public {
|
||||
s1.m[a] = b;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 6328: (143-169): CHC: Assertion violation happens here.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user