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

This commit is contained in:
chriseth
2019-05-28 12:54:33 +02:00
parent d7b5ea6761
commit df96648b1c
9 changed files with 85 additions and 7 deletions
+20
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;
+9 -1
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;
+1 -1
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;
+11 -4
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)
+11 -1
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();
+1
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;
};
@@ -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.
@@ -0,0 +1,8 @@
contract C {
function f() pure public {
assembly {
let x := msize()
}
}
}
// ----
@@ -0,0 +1,12 @@
{
let a := 1
let b := keccak256(1, 1)
sstore(0, msize())
}
// ====
// step: unusedPruner
// ----
// {
// pop(keccak256(1, 1))
// sstore(0, msize())
// }