diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 13ad3644c..e4127012a 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -118,10 +118,10 @@ string YulUtilFunctions::requireOrAssertFunction(bool _assert, Type const* _mess if (!_messageType) return Whiskers(R"( function (condition) { - if iszero(condition) { } + if iszero(condition) { } } )") - ("invalidOrRevert", _assert ? "invalid()" : "revert(0, 0)") + ("error", _assert ? panicFunction() + "()" : "revert(0, 0)") ("functionName", functionName) .render(); @@ -457,7 +457,7 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) string functionName = "checked_add_" + _type.identifier(); // TODO: Consider to add a special case for unsigned 256-bit integers // and use the following instead: - // sum := add(x, y) if lt(sum, x) { revert(0, 0) } + // sum := add(x, y) if lt(sum, x) { () } return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( @@ -466,12 +466,12 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) y := (y) // overflow, if x >= 0 and y > (maxValue - x) - if and(iszero(slt(x, 0)), sgt(y, sub(, x))) { revert(0, 0) } + if and(iszero(slt(x, 0)), sgt(y, sub(, x))) { () } // underflow, if x < 0 and y < (minValue - x) - if and(slt(x, 0), slt(y, sub(, x))) { revert(0, 0) } + if and(slt(x, 0), slt(y, sub(, x))) { () } // overflow, if x > (maxValue - y) - if gt(x, sub(, y)) { revert(0, 0) } + if gt(x, sub(, y)) { () } sum := add(x, y) } @@ -481,6 +481,7 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("cleanupFunction", cleanupFunction(_type)) + ("error", panicFunction()) .render(); }); } @@ -497,16 +498,16 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) y := (y) // overflow, if x > 0, y > 0 and x > (maxValue / y) - if and(and(sgt(x, 0), sgt(y, 0)), gt(x, div(, y))) { revert(0, 0) } + if and(and(sgt(x, 0), sgt(y, 0)), gt(x, div(, y))) { () } // underflow, if x > 0, y < 0 and y < (minValue / x) - if and(and(sgt(x, 0), slt(y, 0)), slt(y, sdiv(, x))) { revert(0, 0) } + if and(and(sgt(x, 0), slt(y, 0)), slt(y, sdiv(, x))) { () } // underflow, if x < 0, y > 0 and x < (minValue / y) - if and(and(slt(x, 0), sgt(y, 0)), slt(x, sdiv(, y))) { revert(0, 0) } + if and(and(slt(x, 0), sgt(y, 0)), slt(x, sdiv(, y))) { () } // overflow, if x < 0, y < 0 and x < (maxValue / y) - if and(and(slt(x, 0), slt(y, 0)), slt(x, sdiv(, y))) { revert(0, 0) } + if and(and(slt(x, 0), slt(y, 0)), slt(x, sdiv(, y))) { () } // overflow, if x != 0 and y > (maxValue / x) - if and(iszero(iszero(x)), gt(y, div(, x))) { revert(0, 0) } + if and(iszero(iszero(x)), gt(y, div(, x))) { () } product := mul(x, y) } @@ -516,6 +517,7 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("cleanupFunction", cleanupFunction(_type)) + ("error", panicFunction()) .render(); }); } @@ -529,13 +531,13 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) function (x, y) -> r { x := (x) y := (y) - if iszero(y) { revert(0, 0) } + if iszero(y) { () } // overflow for minVal / -1 if and( eq(x, ), eq(y, sub(0, 1)) - ) { revert(0, 0) } + ) { () } r := sdiv(x, y) } @@ -544,6 +546,7 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type) ("signed", _type.isSigned()) ("minVal", toCompactHexWithPrefix(u256(_type.minValue()))) ("cleanupFunction", cleanupFunction(_type)) + ("error", panicFunction()) .render(); }); } @@ -557,13 +560,14 @@ string YulUtilFunctions::checkedIntModFunction(IntegerType const& _type) function (x, y) -> r { x := (x) y := (y) - if iszero(y) { revert(0, 0) } + if iszero(y) { () } r := smod(x, y) } )") ("functionName", functionName) ("signed", _type.isSigned()) ("cleanupFunction", cleanupFunction(_type)) + ("error", panicFunction()) .render(); }); } @@ -579,11 +583,11 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) y := (y) // underflow, if y >= 0 and x < (minValue + y) - if and(iszero(slt(y, 0)), slt(x, add(, y))) { revert(0, 0) } + if and(iszero(slt(y, 0)), slt(x, add(, y))) { () } // overflow, if y < 0 and x > (maxValue + y) - if and(slt(y, 0), sgt(x, add(, y))) { revert(0, 0) } + if and(slt(y, 0), sgt(x, add(, y))) { () } - if lt(x, y) { revert(0, 0) } + if lt(x, y) { () } diff := sub(x, y) } @@ -593,6 +597,7 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("cleanupFunction", cleanupFunction(_type)) + ("error", panicFunction()) .render(); }); } @@ -649,7 +654,7 @@ string YulUtilFunctions::overflowCheckedUnsignedExpFunction() for { } gt(exponent, 1) {} { // overflow check for base * base - if gt(base, div(max, base)) { revert(0, 0) } + if gt(base, div(max, base)) { () } if and(exponent, 1) { // no check needed here because base >= power @@ -658,12 +663,13 @@ string YulUtilFunctions::overflowCheckedUnsignedExpFunction() base := mul(base, base) exponent := (exponent) } - if gt(power, div(max, base)) { revert(0, 0) } + if gt(power, div(max, base)) { () } power := mul(power, base) } )") ("functionName", functionName) ("shr_1", shiftRightFunction(1)) + ("error", panicFunction()) .render(); }); } @@ -692,8 +698,8 @@ string YulUtilFunctions::overflowCheckedSignedExpFunction() // overflow check for base * base switch sgt(base, 0) - case 1 { if gt(base, div(max, base)) { revert(0, 0) } } - case 0 { if slt(base, sdiv(max, base)) { revert(0, 0) } } + case 1 { if gt(base, div(max, base)) { () } } + case 0 { if slt(base, sdiv(max, base)) { () } } if and(exponent, 1) { power := base @@ -725,6 +731,7 @@ string YulUtilFunctions::overflowCheckedSignedExpFunction() } )") ("functionName", functionName) + ("error", panicFunction()) ("shr_1", shiftRightFunction(1)) .render(); }); @@ -2889,6 +2896,25 @@ string YulUtilFunctions::revertReasonIfDebug(string const& _message) return revertReasonIfDebug(m_revertStrings, _message); } +string YulUtilFunctions::panicFunction() +{ + string functionName = "panic_error"; + return m_functionCollector.createFunction(functionName, [&]() { + return Whiskers(R"( + function () { + mstore(0, ) + mstore(0x20, 0) + revert(0, 0x24) + } + )") + ("functionName", functionName) + ("sig", (u256(util::FixedHash<4>::Arith(util::FixedHash<4>( + util::keccak256("Panic(uint256)") + ))) << (256 - 32)).str()) + .render(); + }); +} + string YulUtilFunctions::tryDecodeErrorMessageFunction() { string const functionName = "try_decode_error_message"; diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 8394c33af..d2b506b81 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -369,6 +369,9 @@ public: std::string revertReasonIfDebug(std::string const& _message = ""); + /// Reverts with Panic(uint256), potentially adding a special error code in the future. + std::string panicFunction(); + /// Returns the name of a function that decodes an error message. /// signature: () -> arrayPtr ///