diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index ffced74c5..8eca51ed7 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -205,7 +205,7 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory) Whiskers templ(R"( function (headStart, dataEnd) { - if slt(sub(dataEnd, headStart), ) { } + if slt(sub(dataEnd, headStart), ) { () } } )"); @@ -235,7 +235,7 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory) { let offset := (add(headStart, )) - if gt(offset, 0xffffffffffffffff) { } + if gt(offset, 0xffffffffffffffff) { () } let offset := @@ -487,7 +487,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup( else templ("scaleLengthByStride", Whiskers(R"( - if gt(length, ) { } + if gt(length, ) { () } length := mul(length, ) )") ("stride", toCompactHexWithPrefix(fromArrayType.calldataStride())) @@ -1148,7 +1148,7 @@ string ABIFunctions::abiDecodingFunctionArray(ArrayType const& _type, bool _from R"( // function (offset, end) -> array { - if iszero(slt(add(offset, 0x1f), end)) { } + if iszero(slt(add(offset, 0x1f), end)) { () } let length := array := (, length, end) } @@ -1188,7 +1188,7 @@ string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _t let src := offset if gt(add(src, mul(length, )), end) { - + () } for { let i := 0 } lt(i, length) { i := add(i, 1) } { @@ -1241,11 +1241,11 @@ string ABIFunctions::abiDecodingFunctionCalldataArray(ArrayType const& _type) w = Whiskers(R"( // function (offset, end) -> arrayPos, length { - if iszero(slt(add(offset, 0x1f), end)) { } + if iszero(slt(add(offset, 0x1f), end)) { () } length := calldataload(offset) - if gt(length, 0xffffffffffffffff) { } + if gt(length, 0xffffffffffffffff) { () } arrayPos := add(offset, 0x20) - if gt(add(arrayPos, mul(length, )), end) { } + if gt(add(arrayPos, mul(length, )), end) { () } } )"); w("revertStringOffset", revertReasonIfDebug("ABI decoding: invalid calldata array offset")); @@ -1257,7 +1257,7 @@ string ABIFunctions::abiDecodingFunctionCalldataArray(ArrayType const& _type) // function (offset, end) -> arrayPos { arrayPos := offset - if gt(add(arrayPos, mul(, )), end) { } + if gt(add(arrayPos, mul(, )), end) { () } } )"); w("length", toCompactHexWithPrefix(_type.length())); @@ -1288,7 +1288,7 @@ string ABIFunctions::abiDecodingFunctionByteArrayAvailableLength(ArrayType const array := ((length)) mstore(array, length) let dst := add(array, 0x20) - if gt(add(src, length), end) { } + if gt(add(src, length), end) { () } (src, dst, length) } )"); @@ -1312,7 +1312,7 @@ string ABIFunctions::abiDecodingFunctionCalldataStruct(StructType const& _type) Whiskers w{R"( // function (offset, end) -> value { - if slt(sub(end, offset), ) { } + if slt(sub(end, offset), ) { () } value := offset } )"}; @@ -1337,7 +1337,7 @@ string ABIFunctions::abiDecodingFunctionStruct(StructType const& _type, bool _fr Whiskers templ(R"( // function (headStart, end) -> value { - if slt(sub(end, headStart), ) { } + if slt(sub(end, headStart), ) { () } value := () <#members> { @@ -1365,7 +1365,7 @@ string ABIFunctions::abiDecodingFunctionStruct(StructType const& _type, bool _fr Whiskers memberTempl(R"( let offset := (add(headStart, )) - if gt(offset, 0xffffffffffffffff) { } + if gt(offset, 0xffffffffffffffff) { () } let offset := @@ -1441,7 +1441,7 @@ string ABIFunctions::calldataAccessFunction(Type const& _type) Whiskers w(R"( function (base_ref, ptr) -> { let rel_offset_of_tail := calldataload(ptr) - if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(, 1)))) { } + if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(, 1)))) { () } value := add(rel_offset_of_tail, base_ref) } @@ -1453,8 +1453,8 @@ string ABIFunctions::calldataAccessFunction(Type const& _type) w("handleLength", Whiskers(R"( length := calldataload(value) value := add(value, 0x20) - if gt(length, 0xffffffffffffffff) { } - if sgt(base_ref, sub(calldatasize(), mul(length, ))) { } + if gt(length, 0xffffffffffffffff) { () } + if sgt(base_ref, sub(calldatasize(), mul(length, ))) { () } )") ("calldataStride", toCompactHexWithPrefix(arrayType->calldataStride())) // TODO add test @@ -1557,5 +1557,5 @@ size_t ABIFunctions::numVariablesForType(Type const& _type, EncodingOptions cons std::string ABIFunctions::revertReasonIfDebug(std::string const& _message) { - return YulUtilFunctions::revertReasonIfDebug(m_revertStrings, _message); + return m_utils.revertReasonIfDebug(_message); } diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index 8cd858ba0..5d3ef655e 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -273,7 +273,7 @@ private: /// is true), for which it is two. static size_t numVariablesForType(Type const& _type, EncodingOptions const& _options); - /// @returns code that stores @param _message for revert reason + /// @returns the name of a function that uses @param _message for revert reason /// if m_revertStrings is debug. std::string revertReasonIfDebug(std::string const& _message = ""); diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index cddeea472..4a4cba1b7 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -560,7 +560,11 @@ void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _ string CompilerContext::revertReasonIfDebug(string const& _message) { - return YulUtilFunctions::revertReasonIfDebug(m_revertStrings, _message); + return YulUtilFunctions::revertReasonIfDebugBody( + m_revertStrings, + _message, + "mload(" + to_string(CompilerUtils::freeMemoryPointer) + ")" + ); } void CompilerContext::updateSourceLocation() diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 1ec620271..bdf9abc7d 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -268,7 +268,7 @@ public: ); /// If m_revertStrings is debug, @returns inline assembly code that - /// stores @param _message in memory position 0 and reverts. + /// stores @param _message at the free memory pointer and reverts. /// Otherwise returns "revert(0, 0)". std::string revertReasonIfDebug(std::string const& _message = ""); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 5134822bb..c4d4637d2 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -2220,8 +2220,8 @@ string YulUtilFunctions::calldataArrayIndexRangeAccess(ArrayType const& _type) return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( function (offset, length, startIndex, endIndex) -> offsetOut, lengthOut { - if gt(startIndex, endIndex) { } - if gt(endIndex, length) { } + if gt(startIndex, endIndex) { () } + if gt(endIndex, length) { () } offsetOut := add(offset, mul(startIndex, )) lengthOut := sub(endIndex, startIndex) } @@ -2243,13 +2243,13 @@ string YulUtilFunctions::accessCalldataTailFunction(Type const& _type) return Whiskers(R"( function (base_ref, ptr_to_tail) -> addr, length { let rel_offset_of_tail := calldataload(ptr_to_tail) - if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(, 1)))) { } + if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(, 1)))) { () } addr := add(base_ref, rel_offset_of_tail) length := calldataload(addr) - if gt(length, 0xffffffffffffffff) { } + if gt(length, 0xffffffffffffffff) { () } addr := add(addr, 32) - if sgt(addr, sub(calldatasize(), mul(length, ))) { } + if sgt(addr, sub(calldatasize(), mul(length, ))) { () } } )") @@ -4210,42 +4210,52 @@ string YulUtilFunctions::readFromMemoryOrCalldata(Type const& _type, bool _fromC }); } -string YulUtilFunctions::revertReasonIfDebug(RevertStrings revertStrings, string const& _message) -{ - if (revertStrings >= RevertStrings::Debug && !_message.empty()) - { - Whiskers templ(R"({ - mstore(0, ) - mstore(4, 0x20) - mstore(add(4, 0x20), ) - let reasonPos := add(4, 0x40) - <#word> - mstore(add(reasonPos, ), ) - - revert(0, add(reasonPos, )) - })"); - templ("sig", util::selectorFromSignature("Error(string)").str()); - templ("length", to_string(_message.length())); - - size_t words = (_message.length() + 31) / 32; - vector> wordParams(words); - for (size_t i = 0; i < words; ++i) - { - wordParams[i]["offset"] = to_string(i * 32); - wordParams[i]["wordValue"] = formatAsStringOrNumber(_message.substr(32 * i, 32)); - } - templ("word", wordParams); - templ("end", to_string(words * 32)); - - return templ.render(); - } - else - return "revert(0, 0)"; -} - string YulUtilFunctions::revertReasonIfDebug(string const& _message) { - return revertReasonIfDebug(m_revertStrings, _message); + string functionName = "revert_error_" + util::toHex(util::keccak256(_message).asBytes()); + return m_functionCollector.createFunction(functionName, [&](auto&, auto&) -> string { + return revertReasonIfDebugBody(m_revertStrings, allocateUnboundedFunction() + "()", _message); + }); +} + +string YulUtilFunctions::revertReasonIfDebugBody( + RevertStrings _revertStrings, + string const& _allocation, + string const& _message +) +{ + if (_revertStrings < RevertStrings::Debug || _message.empty()) + return "revert(0, 0)"; + + Whiskers templ(R"({ + let start := + let pos := start + mstore(pos, ) + pos := add(pos, 4) + mstore(pos, 0x20) + pos := add(pos, 0x20) + mstore(pos, ) + pos := add(pos, 0x20) + <#word> + mstore(add(pos, ), ) + + revert(start, ) + })"); + templ("allocate", _allocation); + templ("sig", util::selectorFromSignature("Error(string)").str()); + templ("length", to_string(_message.length())); + + size_t words = (_message.length() + 31) / 32; + vector> wordParams(words); + for (size_t i = 0; i < words; ++i) + { + wordParams[i]["offset"] = to_string(i * 32); + wordParams[i]["wordValue"] = formatAsStringOrNumber(_message.substr(32 * i, 32)); + } + templ("word", wordParams); + templ("overallLength", to_string(4 + 0x20 + 0x20 + words * 32)); + + return templ.render(); } string YulUtilFunctions::panicFunction(util::PanicCode _code) diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index f1eaed9fe..b9a46565b 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -453,13 +453,19 @@ public: /// signature: (slot, offset) -> std::string storageSetToZeroFunction(Type const& _type); - /// If revertStrings is debug, @returns inline assembly code that + /// If revertStrings is debug, @returns the name of a function that /// stores @param _message in memory position 0 and reverts. - /// Otherwise returns "revert(0, 0)". - static std::string revertReasonIfDebug(RevertStrings revertStrings, std::string const& _message = ""); - + /// Otherwise returns the name of a function that uses "revert(0, 0)". std::string revertReasonIfDebug(std::string const& _message = ""); + /// @returns the function body of ``revertReasonIfDebug``. + /// Should only be used internally and by the old code generator. + static std::string revertReasonIfDebugBody( + RevertStrings _revertStrings, + std::string const& _allocation, + std::string const& _message + ); + /// Reverts with ``Panic(uint256)`` and the given code. std::string panicFunction(util::PanicCode _code); diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index 228bef068..8ab6b1b17 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -177,8 +177,3 @@ ABIFunctions IRGenerationContext::abiFunctions() { return ABIFunctions(m_evmVersion, m_revertStrings, m_functions); } - -std::string IRGenerationContext::revertReasonIfDebug(std::string const& _message) -{ - return YulUtilFunctions::revertReasonIfDebug(m_revertStrings, _message); -} diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 9976367d9..0f1e9ae1c 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -143,10 +143,6 @@ public: ABIFunctions abiFunctions(); - /// @returns code that stores @param _message for revert reason - /// if m_revertStrings is debug. - std::string revertReasonIfDebug(std::string const& _message = ""); - RevertStrings revertStrings() const { return m_revertStrings; } std::set& subObjectsCreated() { return m_subObjects; } diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 4837b3ff2..84191a5cf 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -852,7 +852,7 @@ string IRGenerator::deployCode(ContractDefinition const& _contract) string IRGenerator::callValueCheck() { - return "if callvalue() { " + m_context.revertReasonIfDebug("Ether sent to non-payable function") + " }"; + return "if callvalue() { " + m_utils.revertReasonIfDebug("Ether sent to non-payable function") + "() }"; } string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) @@ -898,8 +898,8 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) // we revert. delegatecallCheck = "if iszero(called_via_delegatecall) { " + - m_context.revertReasonIfDebug("Non-view function of library called without DELEGATECALL") + - " }"; + m_utils.revertReasonIfDebug("Non-view function of library called without DELEGATECALL") + + "() }"; } templ["delegatecallCheck"] = delegatecallCheck; templ["callValueCheck"] = (type->isPayable() || _contract.isLibrary()) ? "" : callValueCheck(); @@ -950,12 +950,11 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) t("fallback", fallbackCode); } else - t( - "fallback", + t("fallback", ( etherReceiver ? - m_context.revertReasonIfDebug("Unknown signature and no fallback defined") : - m_context.revertReasonIfDebug("Contract does not have fallback nor receive functions") - ); + m_utils.revertReasonIfDebug("Unknown signature and no fallback defined") : + m_utils.revertReasonIfDebug("Contract does not have fallback nor receive functions") + ) + "()"); return t.render(); } diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index e59fde079..a29512163 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -2433,7 +2433,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall( } Whiskers templ(R"( - if iszero(extcodesize(
)) { } + if iszero(extcodesize(
)) { () } // storage for arguments and returned data let := () @@ -2458,7 +2458,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall( := (, add(, )) } )"); - templ("revertNoCode", m_context.revertReasonIfDebug("Target contract does not contain code")); + templ("revertNoCode", m_utils.revertReasonIfDebug("Target contract does not contain code")); templ("pos", m_context.newYulVariable()); templ("end", m_context.newYulVariable()); if (_functionCall.annotation().tryCall)