From 8f5e12c192206b0c7b3b954c4186284388153682 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 26 Feb 2019 19:21:32 +0100 Subject: [PATCH] Make unavailable opcodes errors. --- Changelog.md | 1 + libyul/AsmAnalysis.cpp | 20 +++--- test/libsolidity/InlineAssembly.cpp | 20 +++++- test/libsolidity/SolidityEndToEndTest.cpp | 72 +++++++++++-------- .../SolidityNameAndTypeResolution.cpp | 6 +- test/libsolidity/ViewPureChecker.cpp | 2 +- 6 files changed, 73 insertions(+), 48 deletions(-) diff --git a/Changelog.md b/Changelog.md index b0af39acd..753e4dfb2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Language Features: Compiler Features: * Inline Assembly: Consider ``extcodehash`` as part of Constantinople. + * Inline Assembly: Instructions unavailable to the currently configured EVM are errors now. * SMTChecker: Do not report underflow/overflow if they always revert. This removes false positives when using ``SafeMath``. * Static Analyzer: Warn about expressions with custom types when they have no effect. * Optimizer: Add rule for shifts with constants for Constantinople. diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index b24759e71..abf2e3d1d 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -641,17 +641,17 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio solAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), ""); solAssert(m_dialect->flavour != AsmFlavour::Yul, ""); - auto warningForVM = [=](string const& vmKindMessage) { - m_errorReporter.warning( + auto errorForVM = [=](string const& vmKindMessage) { + m_errorReporter.typeError( _location, "The \"" + boost::to_lower_copy(instructionInfo(_instr).name) + "\" instruction is " + vmKindMessage + - " VMs. " + - "You are currently compiling for \"" + + " VMs " + + " (you are currently compiling for \"" + m_evmVersion.name() + - "\", where it will be interpreted as an invalid instruction." + "\")." ); }; @@ -660,11 +660,11 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio _instr == solidity::Instruction::RETURNDATASIZE ) && !m_evmVersion.supportsReturndata()) { - warningForVM("only available for Byzantium-compatible"); + errorForVM("only available for Byzantium-compatible"); } else if (_instr == solidity::Instruction::STATICCALL && !m_evmVersion.hasStaticCall()) { - warningForVM("only available for Byzantium-compatible"); + errorForVM("only available for Byzantium-compatible"); } else if (( _instr == solidity::Instruction::SHL || @@ -672,15 +672,15 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio _instr == solidity::Instruction::SAR ) && !m_evmVersion.hasBitwiseShifting()) { - warningForVM("only available for Constantinople-compatible"); + errorForVM("only available for Constantinople-compatible"); } else if (_instr == solidity::Instruction::CREATE2 && !m_evmVersion.hasCreate2()) { - warningForVM("only available for Constantinople-compatible"); + errorForVM("only available for Constantinople-compatible"); } else if (_instr == solidity::Instruction::EXTCODEHASH && !m_evmVersion.hasExtCodeHash()) { - warningForVM("only available for Constantinople-compatible"); + errorForVM("only available for Constantinople-compatible"); } else if (_instr == solidity::Instruction::JUMP || _instr == solidity::Instruction::JUMPI || _instr == solidity::Instruction::JUMPDEST) { diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 86b115a51..7e5c47cf2 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -776,36 +776,50 @@ BOOST_AUTO_TEST_CASE(keccak256) BOOST_AUTO_TEST_CASE(returndatasize) { + if (!dev::test::Options::get().evmVersion().supportsReturndata()) + return; BOOST_CHECK(successAssemble("{ let r := returndatasize }")); } BOOST_AUTO_TEST_CASE(returndatasize_functional) { + if (!dev::test::Options::get().evmVersion().supportsReturndata()) + return; BOOST_CHECK(successAssemble("{ let r := returndatasize() }")); } BOOST_AUTO_TEST_CASE(returndatacopy) { + if (!dev::test::Options::get().evmVersion().supportsReturndata()) + return; BOOST_CHECK(successAssemble("{ 64 32 0 returndatacopy }")); } BOOST_AUTO_TEST_CASE(returndatacopy_functional) { + if (!dev::test::Options::get().evmVersion().supportsReturndata()) + return; BOOST_CHECK(successAssemble("{ returndatacopy(0, 32, 64) }")); } BOOST_AUTO_TEST_CASE(staticcall) { + if (!dev::test::Options::get().evmVersion().hasStaticCall()) + return; BOOST_CHECK(successAssemble("{ pop(staticcall(10000, 0x123, 64, 0x10, 128, 0x10)) }")); } BOOST_AUTO_TEST_CASE(create2) { + if (!dev::test::Options::get().evmVersion().hasCreate2()) + return; BOOST_CHECK(successAssemble("{ pop(create2(10, 0x123, 32, 64)) }")); } BOOST_AUTO_TEST_CASE(shift) { + if (!dev::test::Options::get().evmVersion().hasBitwiseShifting()) + return; BOOST_CHECK(successAssemble("{ pop(shl(10, 32)) }")); BOOST_CHECK(successAssemble("{ pop(shr(10, 32)) }")); BOOST_CHECK(successAssemble("{ pop(sar(10, 32)) }")); @@ -815,9 +829,9 @@ BOOST_AUTO_TEST_CASE(shift_constantinople_warning) { if (dev::test::Options::get().evmVersion().hasBitwiseShifting()) return; - CHECK_PARSE_WARNING("{ pop(shl(10, 32)) }", Warning, "The \"shl\" instruction is only available for Constantinople-compatible VMs."); - CHECK_PARSE_WARNING("{ pop(shr(10, 32)) }", Warning, "The \"shr\" instruction is only available for Constantinople-compatible VMs."); - CHECK_PARSE_WARNING("{ pop(sar(10, 32)) }", Warning, "The \"sar\" instruction is only available for Constantinople-compatible VMs."); + CHECK_PARSE_WARNING("{ pop(shl(10, 32)) }", TypeError, "The \"shl\" instruction is only available for Constantinople-compatible VMs"); + CHECK_PARSE_WARNING("{ pop(shr(10, 32)) }", TypeError, "The \"shr\" instruction is only available for Constantinople-compatible VMs"); + CHECK_PARSE_WARNING("{ pop(sar(10, 32)) }", TypeError, "The \"sar\" instruction is only available for Constantinople-compatible VMs"); } BOOST_AUTO_TEST_CASE(jump_warning) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 2a0c493a2..6cec511b3 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -12833,14 +12833,16 @@ BOOST_AUTO_TEST_CASE(revert_with_cause) } } )"; - compileAndRun(sourceCode, 0, "C"); - bool const haveReturndata = dev::test::Options::get().evmVersion().supportsReturndata(); - bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; - ABI_CHECK(callContractFunction("f()"), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "test123") + bytes(28, 0) : bytes()); - ABI_CHECK(callContractFunction("g()"), haveReturndata ? encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0): bytes()); - ABI_CHECK(callContractFunction("h()"), haveReturndata ? encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0): bytes()); - ABI_CHECK(callContractFunction("i()"), haveReturndata ? encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0): bytes()); - ABI_CHECK(callContractFunction("j()"), haveReturndata ? encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0): bytes()); + if (dev::test::Options::get().evmVersion().supportsReturndata()) + { + compileAndRun(sourceCode, 0, "C"); + bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; + ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "test123") + bytes(28, 0)); + ABI_CHECK(callContractFunction("g()"), encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0)); + ABI_CHECK(callContractFunction("h()"), encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0)); + ABI_CHECK(callContractFunction("i()"), encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0)); + ABI_CHECK(callContractFunction("j()"), encodeArgs(0, 0x40, 0x84) + errorSignature + encodeArgs(0x20, 44, "test1234567890123456789012345678901234567890") + bytes(28, 0)); + } } BOOST_AUTO_TEST_CASE(require_with_message) @@ -12905,16 +12907,18 @@ BOOST_AUTO_TEST_CASE(require_with_message) } } )"; - compileAndRun(sourceCode, 0, "C"); - bool const haveReturndata = dev::test::Options::get().evmVersion().supportsReturndata(); - bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; - ABI_CHECK(callContractFunction("f(uint256)", 8), haveReturndata ? encodeArgs(1, 0x40, 0) : bytes()); - ABI_CHECK(callContractFunction("f(uint256)", 5), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 6, "failed") + bytes(28, 0) : bytes()); - ABI_CHECK(callContractFunction("g()"), haveReturndata ? encodeArgs(1, 0x40, 0) : bytes()); - ABI_CHECK(callContractFunction("g()"), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 18, "only on second run") + bytes(28, 0) : bytes()); - ABI_CHECK(callContractFunction("h()"), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 3, "abc") + bytes(28, 0): bytes()); - ABI_CHECK(callContractFunction("i()"), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 3, "abc") + bytes(28, 0): bytes()); - ABI_CHECK(callContractFunction("j()"), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 3, "msg") + bytes(28, 0): bytes()); + if (dev::test::Options::get().evmVersion().supportsReturndata()) + { + compileAndRun(sourceCode, 0, "C"); + bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; + ABI_CHECK(callContractFunction("f(uint256)", 8), encodeArgs(1, 0x40, 0)); + ABI_CHECK(callContractFunction("f(uint256)", 5), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 6, "failed") + bytes(28, 0)); + ABI_CHECK(callContractFunction("g()"), encodeArgs(1, 0x40, 0)); + ABI_CHECK(callContractFunction("g()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 18, "only on second run") + bytes(28, 0)); + ABI_CHECK(callContractFunction("h()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 3, "abc") + bytes(28, 0)); + ABI_CHECK(callContractFunction("i()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 3, "abc") + bytes(28, 0)); + ABI_CHECK(callContractFunction("j()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 3, "msg") + bytes(28, 0)); + } } BOOST_AUTO_TEST_CASE(bubble_up_error_messages) @@ -12949,11 +12953,13 @@ BOOST_AUTO_TEST_CASE(bubble_up_error_messages) } } )"; - compileAndRun(sourceCode, 0, "C"); - bool const haveReturndata = dev::test::Options::get().evmVersion().supportsReturndata(); - bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; - ABI_CHECK(callContractFunction("f()"), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0) : bytes()); - ABI_CHECK(callContractFunction("g()"), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0) : bytes()); + if (dev::test::Options::get().evmVersion().supportsReturndata()) + { + compileAndRun(sourceCode, 0, "C"); + bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; + ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0)); + ABI_CHECK(callContractFunction("g()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0)); + } } BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_transfer) @@ -12985,10 +12991,12 @@ BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_transfer) } } )"; - compileAndRun(sourceCode, 0, "C"); - bool const haveReturndata = dev::test::Options::get().evmVersion().supportsReturndata(); - bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; - ABI_CHECK(callContractFunction("f()"), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0) : bytes()); + if (dev::test::Options::get().evmVersion().supportsReturndata()) + { + compileAndRun(sourceCode, 0, "C"); + bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; + ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0)); + } } BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_create) @@ -13022,10 +13030,12 @@ BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_create) } } )"; - compileAndRun(sourceCode, 0, "C"); - bool const haveReturndata = dev::test::Options::get().evmVersion().supportsReturndata(); - bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; - ABI_CHECK(callContractFunction("f()"), haveReturndata ? encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0) : bytes()); + if (dev::test::Options::get().evmVersion().supportsReturndata()) + { + compileAndRun(sourceCode, 0, "C"); + bytes const errorSignature = bytes{0x08, 0xc3, 0x79, 0xa0}; + ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 0x40, 0x64) + errorSignature + encodeArgs(0x20, 7, "message") + bytes(28, 0)); + } } BOOST_AUTO_TEST_CASE(negative_stack_height) diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 80a542b43..e3f3f077d 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -391,7 +391,7 @@ BOOST_AUTO_TEST_CASE(returndatasize_as_variable) {Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"} }); if (!dev::test::Options::get().evmVersion().supportsReturndata()) - expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"returndatasize\" instruction is only available for Byzantium-compatible VMs."))); + expectations.emplace_back(make_pair(Error::Type::TypeError, std::string("\"returndatasize\" instruction is only available for Byzantium-compatible VMs"))); CHECK_ALLOW_MULTI(text, expectations); } @@ -406,7 +406,7 @@ BOOST_AUTO_TEST_CASE(create2_as_variable) {Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"} }); if (!dev::test::Options::get().evmVersion().hasCreate2()) - expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"create2\" instruction is only available for Constantinople-compatible VMs."))); + expectations.emplace_back(make_pair(Error::Type::TypeError, std::string("\"create2\" instruction is only available for Constantinople-compatible VMs"))); CHECK_ALLOW_MULTI(text, expectations); } @@ -421,7 +421,7 @@ BOOST_AUTO_TEST_CASE(extcodehash_as_variable) {Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"} }); if (!dev::test::Options::get().evmVersion().hasExtCodeHash()) - expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"extcodehash\" instruction is only available for Constantinople-compatible VMs."))); + expectations.emplace_back(make_pair(Error::Type::TypeError, std::string("\"extcodehash\" instruction is only available for Constantinople-compatible VMs"))); CHECK_ALLOW_MULTI(text, expectations); } diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp index 64e526049..176a349d3 100644 --- a/test/libsolidity/ViewPureChecker.cpp +++ b/test/libsolidity/ViewPureChecker.cpp @@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(assembly_staticcall) } )"; if (!dev::test::Options::get().evmVersion().hasStaticCall()) - CHECK_WARNING(text, "\"staticcall\" instruction is only available for Byzantium-compatible"); + CHECK_ERROR(text, TypeError, "\"staticcall\" instruction is only available for Byzantium-compatible"); else CHECK_SUCCESS_NO_WARNINGS(text); }