Warn about using loose inline assembly features as experimental 0.5.0 feature.

This commit is contained in:
chriseth 2018-02-15 15:18:09 +01:00
parent 14b12ae745
commit fd1662d1c4
8 changed files with 65 additions and 10 deletions

View File

@ -280,7 +280,8 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
// Will be re-generated later with correct information // Will be re-generated later with correct information
// We use the latest EVM version because we will re-run it anyway. // We use the latest EVM version because we will re-run it anyway.
assembly::AsmAnalysisInfo analysisInfo; assembly::AsmAnalysisInfo analysisInfo;
assembly::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations()); boost::optional<Error::Type> errorTypeForLoose = m_experimental050Mode ? Error::Type::SyntaxError : Error::Type::Warning;
assembly::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations());
return false; return false;
} }

View File

@ -894,10 +894,15 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
}; };
solAssert(!_inlineAssembly.annotation().analysisInfo, ""); solAssert(!_inlineAssembly.annotation().analysisInfo, "");
_inlineAssembly.annotation().analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); _inlineAssembly.annotation().analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
boost::optional<Error::Type> errorTypeForLoose =
m_scope->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050) ?
Error::Type::SyntaxError :
Error::Type::Warning;
assembly::AsmAnalyzer analyzer( assembly::AsmAnalyzer analyzer(
*_inlineAssembly.annotation().analysisInfo, *_inlineAssembly.annotation().analysisInfo,
m_errorReporter, m_errorReporter,
m_evmVersion, m_evmVersion,
errorTypeForLoose,
assembly::AsmFlavour::Loose, assembly::AsmFlavour::Loose,
identifierAccess identifierAccess
); );

View File

@ -330,6 +330,7 @@ void CompilerContext::appendInlineAssembly(
analysisInfo, analysisInfo,
errorReporter, errorReporter,
m_evmVersion, m_evmVersion,
boost::none,
assembly::AsmFlavour::Strict, assembly::AsmFlavour::Strict,
identifierAccess.resolve identifierAccess.resolve
).analyze(*parserResult); ).analyze(*parserResult);

View File

@ -54,7 +54,10 @@ bool AsmAnalyzer::analyze(Block const& _block)
bool AsmAnalyzer::operator()(Label const& _label) bool AsmAnalyzer::operator()(Label const& _label)
{ {
solAssert(m_flavour == AsmFlavour::Loose, ""); checkLooseFeature(
_label.location,
"The use of labels is deprecated. Please use \"if\", \"switch\", \"for\" or function calls instead."
);
m_info.stackHeightInfo[&_label] = m_stackHeight; m_info.stackHeightInfo[&_label] = m_stackHeight;
warnOnInstructions(solidity::Instruction::JUMPDEST, _label.location); warnOnInstructions(solidity::Instruction::JUMPDEST, _label.location);
return true; return true;
@ -62,7 +65,10 @@ bool AsmAnalyzer::operator()(Label const& _label)
bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction) bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction)
{ {
solAssert(m_flavour == AsmFlavour::Loose, ""); checkLooseFeature(
_instruction.location,
"The use of non-functional instructions is deprecated. Please use functional notation instead."
);
auto const& info = instructionInfo(_instruction.instruction); auto const& info = instructionInfo(_instruction.instruction);
m_stackHeight += info.ret - info.args; m_stackHeight += info.ret - info.args;
m_info.stackHeightInfo[&_instruction] = m_stackHeight; m_info.stackHeightInfo[&_instruction] = m_stackHeight;
@ -170,18 +176,31 @@ bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr)
bool AsmAnalyzer::operator()(assembly::ExpressionStatement const& _statement) bool AsmAnalyzer::operator()(assembly::ExpressionStatement const& _statement)
{ {
size_t initialStackHeight = m_stackHeight; int initialStackHeight = m_stackHeight;
bool success = boost::apply_visitor(*this, _statement.expression); bool success = boost::apply_visitor(*this, _statement.expression);
if (m_flavour != AsmFlavour::Loose) if (m_stackHeight != initialStackHeight && (m_flavour != AsmFlavour::Loose || m_errorTypeForLoose))
if (!expectDeposit(0, initialStackHeight, _statement.location)) {
Error::Type errorType = m_flavour == AsmFlavour::Loose ? *m_errorTypeForLoose : Error::Type::TypeError;
string msg =
"Top-level expressions are not supposed to return values (this expression returns " +
boost::lexical_cast<string>(m_stackHeight - initialStackHeight) +
" value" +
(m_stackHeight - initialStackHeight == 1 ? "" : "s") +
"). Use ``pop()`` or assign them.";
m_errorReporter.error(errorType, _statement.location, msg);
if (errorType != Error::Type::Warning)
success = false; success = false;
}
m_info.stackHeightInfo[&_statement] = m_stackHeight; m_info.stackHeightInfo[&_statement] = m_stackHeight;
return success; return success;
} }
bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment) bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment)
{ {
solAssert(m_flavour == AsmFlavour::Loose, ""); checkLooseFeature(
_assignment.location,
"The use of stack assignment is deprecated. Please use assignment in functional notation instead."
);
bool success = checkAssignment(_assignment.variableName, size_t(-1)); bool success = checkAssignment(_assignment.variableName, size_t(-1));
m_info.stackHeightInfo[&_assignment] = m_stackHeight; m_info.stackHeightInfo[&_assignment] = m_stackHeight;
return success; return success;
@ -577,10 +596,22 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio
); );
if (_instr == solidity::Instruction::JUMP || _instr == solidity::Instruction::JUMPI || _instr == solidity::Instruction::JUMPDEST) if (_instr == solidity::Instruction::JUMP || _instr == solidity::Instruction::JUMPI || _instr == solidity::Instruction::JUMPDEST)
m_errorReporter.warning( {
solAssert(m_flavour == AsmFlavour::Loose, "");
m_errorReporter.error(
m_errorTypeForLoose ? *m_errorTypeForLoose : Error::Type::Warning,
_location, _location,
"Jump instructions and labels are low-level EVM features that can lead to " "Jump instructions and labels are low-level EVM features that can lead to "
"incorrect stack access. Because of that they are discouraged. " "incorrect stack access. Because of that they are discouraged. "
"Please consider using \"switch\", \"if\" or \"for\" statements instead." "Please consider using \"switch\", \"if\" or \"for\" statements instead."
); );
} }
}
void AsmAnalyzer::checkLooseFeature(SourceLocation const& _location, string const& _description)
{
if (m_flavour != AsmFlavour::Loose)
solAssert(false, _description);
else if (m_errorTypeForLoose)
m_errorReporter.error(*m_errorTypeForLoose, _location, _description);
}

View File

@ -30,6 +30,7 @@
#include <libsolidity/inlineasm/AsmDataForward.h> #include <libsolidity/inlineasm/AsmDataForward.h>
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include <boost/optional.hpp>
#include <functional> #include <functional>
#include <memory> #include <memory>
@ -56,9 +57,17 @@ public:
AsmAnalysisInfo& _analysisInfo, AsmAnalysisInfo& _analysisInfo,
ErrorReporter& _errorReporter, ErrorReporter& _errorReporter,
EVMVersion _evmVersion, EVMVersion _evmVersion,
boost::optional<Error::Type> _errorTypeForLoose,
AsmFlavour _flavour = AsmFlavour::Loose, AsmFlavour _flavour = AsmFlavour::Loose,
julia::ExternalIdentifierAccess::Resolver const& _resolver = julia::ExternalIdentifierAccess::Resolver() julia::ExternalIdentifierAccess::Resolver const& _resolver = julia::ExternalIdentifierAccess::Resolver()
): m_resolver(_resolver), m_info(_analysisInfo), m_errorReporter(_errorReporter), m_evmVersion(_evmVersion), m_flavour(_flavour) {} ):
m_resolver(_resolver),
m_info(_analysisInfo),
m_errorReporter(_errorReporter),
m_evmVersion(_evmVersion),
m_flavour(_flavour),
m_errorTypeForLoose(_errorTypeForLoose)
{}
bool analyze(assembly::Block const& _block); bool analyze(assembly::Block const& _block);
@ -91,6 +100,11 @@ private:
void expectValidType(std::string const& type, SourceLocation const& _location); void expectValidType(std::string const& type, SourceLocation const& _location);
void warnOnInstructions(solidity::Instruction _instr, SourceLocation const& _location); void warnOnInstructions(solidity::Instruction _instr, SourceLocation const& _location);
/// Depending on @a m_flavour and @a m_errorTypeForLoose, throws an internal compiler
/// exception (if the flavour is not Loose), reports an error/warning
/// (if m_errorTypeForLoose is set) or does nothing.
void checkLooseFeature(SourceLocation const& _location, std::string const& _description);
int m_stackHeight = 0; int m_stackHeight = 0;
julia::ExternalIdentifierAccess::Resolver m_resolver; julia::ExternalIdentifierAccess::Resolver m_resolver;
Scope* m_currentScope = nullptr; Scope* m_currentScope = nullptr;
@ -101,6 +115,7 @@ private:
ErrorReporter& m_errorReporter; ErrorReporter& m_errorReporter;
EVMVersion m_evmVersion; EVMVersion m_evmVersion;
AsmFlavour m_flavour = AsmFlavour::Loose; AsmFlavour m_flavour = AsmFlavour::Loose;
boost::optional<Error::Type> m_errorTypeForLoose;
}; };
} }

View File

@ -91,7 +91,7 @@ bool AssemblyStack::analyze(assembly::Block const& _block, Scanner const* _scann
bool AssemblyStack::analyzeParsed() bool AssemblyStack::analyzeParsed()
{ {
m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, m_evmVersion, languageToAsmFlavour(m_language)); assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, m_evmVersion, boost::none, languageToAsmFlavour(m_language));
m_analysisSuccessful = analyzer.analyze(*m_parserResult); m_analysisSuccessful = analyzer.analyze(*m_parserResult);
return m_analysisSuccessful; return m_analysisSuccessful;
} }

View File

@ -67,6 +67,7 @@ pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::julia::test:
*analysisInfo, *analysisInfo,
errorReporter, errorReporter,
dev::test::Options::get().evmVersion(), dev::test::Options::get().evmVersion(),
boost::none,
flavour flavour
); );
if (analyzer.analyze(*parserResult)) if (analyzer.analyze(*parserResult))

View File

@ -60,6 +60,7 @@ bool parse(string const& _source, ErrorReporter& errorReporter)
analysisInfo, analysisInfo,
errorReporter, errorReporter,
dev::test::Options::get().evmVersion(), dev::test::Options::get().evmVersion(),
boost::none,
assembly::AsmFlavour::IULIA assembly::AsmFlavour::IULIA
)).analyze(*parserResult); )).analyze(*parserResult);
} }