Do not allow msize in inline assembly if the Yul optimizer is active.

This commit is contained in:
chriseth 2019-05-27 14:01:53 +02:00
parent d7b5ea6761
commit df96648b1c
9 changed files with 85 additions and 7 deletions

View File

@ -21,6 +21,9 @@
#include <libsolidity/ast/ExperimentalFeatures.h>
#include <libsolidity/interface/Version.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/AsmData.h>
#include <liblangutil/ErrorReporter.h>
#include <liblangutil/SemVerHandler.h>
@ -254,6 +257,23 @@ bool SyntaxChecker::visit(UnaryOperation const& _operation)
return true;
}
bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly)
{
if (!m_useYulOptimizer)
return false;
if (yul::SideEffectsCollector(
_inlineAssembly.dialect(),
_inlineAssembly.operations()
).containsMSize())
m_errorReporter.syntaxError(
_inlineAssembly.location(),
"The msize instruction cannot be used when the Yul optimizer is activated because "
"it can change its semantics. Either disable the Yul optimizer or do not use the instruction."
);
return false;
}
bool SyntaxChecker::visit(PlaceholderStatement const&)
{
m_placeholderFound = true;

View File

@ -39,12 +39,16 @@ namespace solidity
* - whether a modifier contains at least one '_'
* - issues deprecation warnings for unary '+'
* - issues deprecation warning for throw
* - whether the msize instruction is used and the Yul optimizer is enabled at the same time.
*/
class SyntaxChecker: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
SyntaxChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
SyntaxChecker(langutil::ErrorReporter& _errorReporter, bool _useYulOptimizer):
m_errorReporter(_errorReporter),
m_useYulOptimizer(_useYulOptimizer)
{}
bool checkSyntax(ASTNode const& _astRoot);
@ -75,6 +79,8 @@ private:
bool visit(UnaryOperation const& _operation) override;
bool visit(InlineAssembly const& _inlineAssembly) override;
bool visit(PlaceholderStatement const& _placeholderStatement) override;
bool visit(ContractDefinition const& _contract) override;
@ -88,6 +94,8 @@ private:
langutil::ErrorReporter& m_errorReporter;
bool m_useYulOptimizer = false;
/// Flag that indicates whether a function modifier actually contains '_'.
bool m_placeholderFound = false;

View File

@ -250,7 +250,7 @@ bool CompilerStack::analyze()
bool noErrors = true;
try {
SyntaxChecker syntaxChecker(m_errorReporter);
SyntaxChecker syntaxChecker(m_errorReporter, m_optimiserSettings.runYulOptimiser);
for (Source const* source: m_sourceOrder)
if (!syntaxChecker.checkSyntax(*source->ast))
noErrors = false;

View File

@ -10082,8 +10082,11 @@ BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size)
}
}
)";
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("f()"), encodeArgs(0x40, 0x40, 0x20 + 256, 0x260));
if (!m_optimiserSettings.runYulOptimiser)
{
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("f()"), encodeArgs(0x40, 0x40, 0x20 + 256, 0x260));
}
}
BOOST_AUTO_TEST_CASE(memory_arrays_of_various_sizes)
@ -11273,8 +11276,12 @@ BOOST_AUTO_TEST_CASE(correctly_initialize_memory_array_in_constructor)
}
}
)";
compileAndRun(sourceCode, 0, "C");
ABI_CHECK(callContractFunction("success()"), encodeArgs(u256(1)));
// Cannot run against yul optimizer because of msize
if (!m_optimiserSettings.runYulOptimiser)
{
compileAndRun(sourceCode, 0, "C");
ABI_CHECK(callContractFunction("success()"), encodeArgs(u256(1)));
}
}
BOOST_AUTO_TEST_CASE(return_does_not_skip_modifier)

View File

@ -60,6 +60,12 @@ SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion
file.exceptions(ios::badbit);
m_source = parseSourceAndSettings(file);
if (m_settings.count("optimize-yul"))
{
m_optimiseYul = true;
m_validatedSettings["optimize-yul"] = "true";
m_settings.erase("optimize-yul");
}
m_expectations = parseExpectations(file);
}
@ -69,7 +75,11 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
compiler().reset();
compiler().setSources({{"", versionPragma + m_source}});
compiler().setEVMVersion(m_evmVersion);
compiler().setOptimiserSettings(
m_optimiseYul ?
OptimiserSettings::full() :
OptimiserSettings::minimal()
);
if (compiler().parse())
compiler().analyze();

View File

@ -82,6 +82,7 @@ protected:
std::string m_source;
std::vector<SyntaxTestError> m_expectations;
std::vector<SyntaxTestError> m_errorList;
bool m_optimiseYul = false;
langutil::EVMVersion const m_evmVersion;
};

View File

@ -0,0 +1,12 @@
contract C {
function f() pure public {
assembly {
let x := msize()
}
}
}
// ====
// optimize-yul: true
// ----
// Warning: The Yul optimiser is still experimental. Do not use it in production unless correctness of generated code is verified with extensive tests.
// SyntaxError: (52-101): The msize instruction cannot be used when the Yul optimizer is activated because it can change its semantics. Either disable the Yul optimizer or do not use the instruction.

View File

@ -0,0 +1,8 @@
contract C {
function f() pure public {
assembly {
let x := msize()
}
}
}
// ----

View File

@ -0,0 +1,12 @@
{
let a := 1
let b := keccak256(1, 1)
sstore(0, msize())
}
// ====
// step: unusedPruner
// ----
// {
// pop(keccak256(1, 1))
// sstore(0, msize())
// }