mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8178 from ethereum/internal_revert_strings
Internal reverts with reason in debug mode
This commit is contained in:
@@ -169,26 +169,32 @@ BOOST_AUTO_TEST_CASE(location_test)
|
||||
if (solidity::test::CommonOptions::get().optimize)
|
||||
locations =
|
||||
vector<SourceLocation>(4, SourceLocation{2, 82, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{8, 17, codegenCharStream}) +
|
||||
vector<SourceLocation>(3, SourceLocation{5, 7, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{30, 31, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{5, 14, codegenCharStream}) +
|
||||
vector<SourceLocation>(3, SourceLocation{2, 4, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{27, 28, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{20, 32, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{5, 7, codegenCharStream}) +
|
||||
vector<SourceLocation>(19, SourceLocation{2, 82, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{24, 25, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{17, 29, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{2, 4, codegenCharStream}) +
|
||||
vector<SourceLocation>(16, SourceLocation{2, 82, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{12, 13, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{9, 10, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{2, 14, codegenCharStream}) +
|
||||
vector<SourceLocation>(21, SourceLocation{20, 79, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{72, 74, sourceCode}) +
|
||||
vector<SourceLocation>(2, SourceLocation{20, 79, sourceCode});
|
||||
else
|
||||
locations =
|
||||
vector<SourceLocation>(4, SourceLocation{2, 82, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{8, 17, codegenCharStream}) +
|
||||
vector<SourceLocation>(3, SourceLocation{5, 7, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{30, 31, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{5, 14, codegenCharStream}) +
|
||||
vector<SourceLocation>(3, SourceLocation{2, 4, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{27, 28, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{20, 32, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{5, 7, codegenCharStream}) +
|
||||
vector<SourceLocation>(hasShifts ? 19 : 20, SourceLocation{2, 82, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{24, 25, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{17, 29, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{2, 4, codegenCharStream}) +
|
||||
vector<SourceLocation>(hasShifts ? 16 : 17, SourceLocation{2, 82, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{12, 13, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{9, 10, codegenCharStream}) +
|
||||
vector<SourceLocation>(1, SourceLocation{2, 14, codegenCharStream}) +
|
||||
vector<SourceLocation>(24, SourceLocation{20, 79, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{49, 58, sourceCode}) +
|
||||
vector<SourceLocation>(1, SourceLocation{72, 74, sourceCode}) +
|
||||
|
||||
@@ -70,6 +70,16 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer
|
||||
}
|
||||
m_settings.erase("ABIEncoderV1Only");
|
||||
}
|
||||
|
||||
if (m_settings.count("revertStrings"))
|
||||
{
|
||||
auto revertStrings = revertStringsFromString(m_settings["revertStrings"]);
|
||||
if (revertStrings)
|
||||
m_revertStrings = *revertStrings;
|
||||
m_validatedSettings["revertStrings"] = revertStringsToString(m_revertStrings);
|
||||
m_settings.erase("revertStrings");
|
||||
}
|
||||
|
||||
parseExpectations(file);
|
||||
soltestAssert(!m_tests.empty(), "No tests specified in " + _filename);
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ bytes SolidityExecutionFramework::compileContract(
|
||||
m_compiler.setEVMVersion(m_evmVersion);
|
||||
m_compiler.setOptimiserSettings(m_optimiserSettings);
|
||||
m_compiler.enableIRGeneration(m_compileViaYul);
|
||||
m_compiler.setRevertStringBehaviour(m_revertStrings);
|
||||
if (!m_compiler.compile())
|
||||
{
|
||||
langutil::SourceReferenceFormatter formatter(std::cerr);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <test/ExecutionFramework.h>
|
||||
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/interface/DebugSettings.h>
|
||||
|
||||
#include <libyul/AssemblyStack.h>
|
||||
|
||||
@@ -67,6 +68,8 @@ public:
|
||||
protected:
|
||||
solidity::frontend::CompilerStack m_compiler;
|
||||
bool m_compileViaYul = false;
|
||||
RevertStrings m_revertStrings = RevertStrings::Default;
|
||||
|
||||
};
|
||||
|
||||
} // end namespaces
|
||||
|
||||
@@ -139,7 +139,10 @@ bytes compileFirstExpression(
|
||||
FirstExpressionExtractor extractor(*contract);
|
||||
BOOST_REQUIRE(extractor.expression() != nullptr);
|
||||
|
||||
CompilerContext context(solidity::test::CommonOptions::get().evmVersion());
|
||||
CompilerContext context(
|
||||
solidity::test::CommonOptions::get().evmVersion(),
|
||||
RevertStrings::Default
|
||||
);
|
||||
context.resetVisitedNodes(contract);
|
||||
context.setInheritanceHierarchy(inheritanceHierarchy);
|
||||
unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack
|
||||
@@ -152,7 +155,6 @@ bytes compileFirstExpression(
|
||||
|
||||
ExpressionCompiler(
|
||||
context,
|
||||
RevertStrings::Default,
|
||||
solidity::test::CommonOptions::get().optimize
|
||||
).compile(*extractor.expression());
|
||||
|
||||
|
||||
@@ -366,14 +366,15 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
|
||||
BOOST_CHECK(contract["evm"]["assembly"].isString());
|
||||
BOOST_CHECK(contract["evm"]["assembly"].asString().find(
|
||||
" /* \"fileA\":0:14 contract A { } */\n mstore(0x40, 0x80)\n "
|
||||
"callvalue\n /* \"--CODEGEN--\":8:17 */\n dup1\n "
|
||||
"/* \"--CODEGEN--\":5:7 */\n iszero\n tag_1\n jumpi\n "
|
||||
"/* \"--CODEGEN--\":30:31 */\n 0x00\n /* \"--CODEGEN--\":27:28 */\n "
|
||||
"dup1\n /* \"--CODEGEN--\":20:32 */\n revert\n /* \"--CODEGEN--\":5:7 */\n"
|
||||
"callvalue\n /* \"--CODEGEN--\":5:14 */\n dup1\n "
|
||||
"/* \"--CODEGEN--\":2:4 */\n iszero\n tag_1\n jumpi\n "
|
||||
"/* \"--CODEGEN--\":27:28 */\n 0x00\n /* \"--CODEGEN--\":24:25 */\n "
|
||||
"dup1\n /* \"--CODEGEN--\":17:29 */\n revert\n /* \"--CODEGEN--\":2:4 */\n"
|
||||
"tag_1:\n /* \"fileA\":0:14 contract A { } */\n pop\n dataSize(sub_0)\n dup1\n "
|
||||
"dataOffset(sub_0)\n 0x00\n codecopy\n 0x00\n return\nstop\n\nsub_0: assembly {\n "
|
||||
"/* \"fileA\":0:14 contract A { } */\n mstore(0x40, 0x80)\n 0x00\n "
|
||||
"dup1\n revert\n\n auxdata: 0xa26469706673582212"
|
||||
"/* \"fileA\":0:14 contract A { } */\n mstore(0x40, 0x80)\n "
|
||||
"/* \"--CODEGEN--\":12:13 */\n 0x00\n /* \"--CODEGEN--\":9:10 */\n "
|
||||
"dup1\n /* \"--CODEGEN--\":2:14 */\n revert\n\n auxdata: 0xa26469706673582212"
|
||||
) == 0);
|
||||
BOOST_CHECK(contract["evm"]["gasEstimates"].isObject());
|
||||
BOOST_CHECK_EQUAL(contract["evm"]["gasEstimates"].size(), 1);
|
||||
@@ -397,15 +398,15 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH\",\"value\":\"40\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"MSTORE\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"CALLVALUE\"},"
|
||||
"{\"begin\":8,\"end\":17,\"name\":\"DUP1\"},"
|
||||
"{\"begin\":5,\"end\":7,\"name\":\"ISZERO\"},"
|
||||
"{\"begin\":5,\"end\":7,\"name\":\"PUSH [tag]\",\"value\":\"1\"},"
|
||||
"{\"begin\":5,\"end\":7,\"name\":\"JUMPI\"},"
|
||||
"{\"begin\":30,\"end\":31,\"name\":\"PUSH\",\"value\":\"0\"},"
|
||||
"{\"begin\":27,\"end\":28,\"name\":\"DUP1\"},"
|
||||
"{\"begin\":20,\"end\":32,\"name\":\"REVERT\"},"
|
||||
"{\"begin\":5,\"end\":7,\"name\":\"tag\",\"value\":\"1\"},"
|
||||
"{\"begin\":5,\"end\":7,\"name\":\"JUMPDEST\"},"
|
||||
"{\"begin\":5,\"end\":14,\"name\":\"DUP1\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"ISZERO\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"PUSH [tag]\",\"value\":\"1\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"JUMPI\"},"
|
||||
"{\"begin\":27,\"end\":28,\"name\":\"PUSH\",\"value\":\"0\"},"
|
||||
"{\"begin\":24,\"end\":25,\"name\":\"DUP1\"},"
|
||||
"{\"begin\":17,\"end\":29,\"name\":\"REVERT\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"tag\",\"value\":\"1\"},"
|
||||
"{\"begin\":2,\"end\":4,\"name\":\"JUMPDEST\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"POP\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"PUSH #[$]\",\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"},"
|
||||
"{\"begin\":0,\"end\":14,\"name\":\"DUP1\"},"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
contract C {
|
||||
function f(uint256 start, uint256 end, uint256[] calldata arr) external pure {
|
||||
arr[start:end];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// f(uint256,uint256,uint256[]): 2, 1, 0x80, 3, 1, 2, 3 -> FAILURE, hex"08c379a0", 0x20, 22, "Slice starts after end"
|
||||
// f(uint256,uint256,uint256[]): 1, 5, 0x80, 3, 1, 2, 3 -> FAILURE, hex"08c379a0", 0x20, 28, "Slice is greater than length"
|
||||
@@ -0,0 +1,15 @@
|
||||
contract A {
|
||||
function g() public { revert("fail"); }
|
||||
}
|
||||
|
||||
contract C {
|
||||
A a = new A();
|
||||
function f() public {
|
||||
a.g();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// f() -> FAILURE, hex"08c379a0", 0x20, 4, "fail"
|
||||
@@ -0,0 +1,11 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
contract C {
|
||||
function f(uint256[][] calldata a) external returns (uint) {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// f(uint256[][]): 0x20, 1 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI decoding: invalid calldata a", "rray stride"
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
contract C {
|
||||
function f(uint256[][2][] calldata x) external returns (uint256) {
|
||||
x[0];
|
||||
return 23;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// f(uint256[][2][]): 0x20, 0x01, 0x20, 0x00 -> FAILURE, hex"08c379a0", 0x20, 28, "Invalid calldata tail offset"
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
contract C {
|
||||
function f(uint256[][2][] calldata x) external returns (uint256) {
|
||||
return 42;
|
||||
}
|
||||
function g(uint256[][2][] calldata x) external returns (uint256) {
|
||||
return this.f(x);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// g(uint256[][2][]): 0x20, 0x01, 0x20, 0x00 -> FAILURE, hex"08c379a0", 0x20, 30, "Invalid calldata access offset"
|
||||
@@ -0,0 +1,11 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
contract C {
|
||||
function f(uint256[][] calldata x) external returns (uint256) {
|
||||
return x[0].length;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// f(uint256[][]): 0x20, 1, 0x20, 0x0100000000000000000000 -> FAILURE, hex"08c379a0", 0x20, 28, "Invalid calldata tail length"
|
||||
@@ -0,0 +1,11 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
contract C {
|
||||
function f(uint a, uint[] calldata b, uint c) external pure returns (uint) {
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// f(uint256,uint256[],uint256): 6, 0x60, 9, 0x1000000000000000000000000000000000000000000000000000000000000002, 1, 2 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI decoding: invalid calldata a", "rray length"
|
||||
@@ -0,0 +1,11 @@
|
||||
contract C {
|
||||
function d(bytes memory _data) public pure returns (uint8) {
|
||||
return abi.decode(_data, (uint8));
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ABIEncoderV1Only: true
|
||||
// ----
|
||||
// d(bytes): 0x20, 0x01, 0x0000000000000000000000000000000000000000000000000000000000000000 -> FAILURE, hex"08c379a0", 0x20, 18, "Calldata too short"
|
||||
@@ -0,0 +1,12 @@
|
||||
contract C {
|
||||
function f() external {}
|
||||
function g() external {
|
||||
C c = C(0x0000000000000000000000000000000000000000000000000000000000000000);
|
||||
c.f();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// g() -> FAILURE, hex"08c379a0", 0x20, 37, "Target contract does not contain", " code"
|
||||
@@ -0,0 +1,12 @@
|
||||
contract C {
|
||||
enum E {X, Y}
|
||||
function f(E[] calldata arr) external {
|
||||
arr[1];
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ABIEncoderV1Only: true
|
||||
// ----
|
||||
// f(uint8[]): 0x20, 2, 3, 3 -> FAILURE, hex"08c379a0", 0x20, 17, "Enum out of range"
|
||||
@@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
function f() public {}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// f(), 1 ether -> FAILURE, hex"08c379a0", 0x20, 34, "Ether sent to non-payable functi", "on"
|
||||
// () -> FAILURE, hex"08c379a0", 0x20, 53, "Contract does not have fallback ", "nor receive functions"
|
||||
@@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
function t(uint) public pure {}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// compileViaYul: true
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// t(uint256) -> FAILURE, hex"08c379a0", 0x20, 34, "ABI decoding: tuple data too sho", "rt"
|
||||
@@ -0,0 +1,13 @@
|
||||
contract C {
|
||||
function d(bytes memory _data) public pure returns (uint8) {
|
||||
return abi.decode(_data, (uint8));
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ABIEncoderV1Only: true
|
||||
// ----
|
||||
// d(bytes): 0x20, 0x20, 0x0000000000000000000000000000000000000000000000000000000000000000 -> 0
|
||||
// d(bytes): 0x100, 0x20, 0x0000000000000000000000000000000000000000000000000000000000000000 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI calldata decoding: invalid h", "ead pointer"
|
||||
// d(bytes): 0x20, 0x100, 0x0000000000000000000000000000000000000000000000000000000000000000 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI calldata decoding: invalid d", "ata pointer"
|
||||
@@ -0,0 +1,20 @@
|
||||
contract C {
|
||||
function dyn(uint ptr, uint start, uint x) public returns (bytes memory a) {
|
||||
assembly {
|
||||
mstore(0, start)
|
||||
mstore(start, add(start, 1))
|
||||
return(ptr, x)
|
||||
}
|
||||
}
|
||||
function f(uint ptr, uint start, uint x) public returns (bool) {
|
||||
this.dyn(ptr, start, x);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ABIEncoderV1Only: true
|
||||
// ----
|
||||
// f(uint256,uint256,uint256): 0, 0x200, 0x60 -> FAILURE, hex"08c379a0", 0x20, 39, "ABI memory decoding: invalid dat", "a start"
|
||||
// f(uint256,uint256,uint256): 0, 0x20, 0x60 -> FAILURE, hex"08c379a0", 0x20, 40, "ABI memory decoding: invalid dat", "a length"
|
||||
@@ -0,0 +1,16 @@
|
||||
library L {
|
||||
function g() external {}
|
||||
}
|
||||
contract C {
|
||||
function f() public returns (bytes memory) {
|
||||
(bool success, bytes memory result) = address(L).call(abi.encodeWithSignature("g()"));
|
||||
assert(!success);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// library: L
|
||||
// f() -> 32, 132, 3963877391197344453575983046348115674221700746820753546331534351508065746944, 862718293348820473429344482784628181556388621521298319395315527974912, 1518017211910606845658622928256476421055725129218887721595913401102969, 14649601406562900601407788686537400806574002225747213573947654179243427889152, 0
|
||||
@@ -0,0 +1,9 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
contract C {
|
||||
function f(uint[] memory a) public pure returns (uint) { return 7; }
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// f(uint256[]): 0x20, 1 -> FAILURE, hex"08c379a0", 0x20, 43, "ABI decoding: invalid calldata a", "rray stride"
|
||||
@@ -0,0 +1,9 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
contract C {
|
||||
function e(bytes memory a) public pure returns (uint) { return 7; }
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// e(bytes): 0x20, 7 -> FAILURE, hex"08c379a0", 0x20, 39, "ABI decoding: invalid byte array", " length"
|
||||
@@ -0,0 +1,27 @@
|
||||
contract A {
|
||||
receive() external payable {
|
||||
revert("no_receive");
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
A a = new A();
|
||||
receive() external payable {}
|
||||
function f() public {
|
||||
address(a).transfer(1 wei);
|
||||
}
|
||||
function h() public {
|
||||
address(a).transfer(100 ether);
|
||||
}
|
||||
function g() public view returns (uint) {
|
||||
return address(this).balance;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// (), 10 ether ->
|
||||
// g() -> 10
|
||||
// f() -> FAILURE, hex"08c379a0", 0x20, 10, "no_receive"
|
||||
// h() -> FAILURE
|
||||
@@ -0,0 +1,8 @@
|
||||
contract A {
|
||||
receive () external payable {}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >=byzantium
|
||||
// revertStrings: debug
|
||||
// ----
|
||||
// (): hex"00" -> FAILURE, hex"08c379a0", 0x20, 41, "Unknown signature and no fallbac", "k defined"
|
||||
Reference in New Issue
Block a user