Make unavailable opcodes errors.

This commit is contained in:
chriseth 2019-02-26 19:21:32 +01:00
parent ab33ff1408
commit 8f5e12c192
6 changed files with 73 additions and 48 deletions

View File

@ -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.

View File

@ -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)
{

View File

@ -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)

View File

@ -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)

View File

@ -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);
}

View File

@ -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);
}