Inline assembly without memory effects is implicitly memory safe.

This commit is contained in:
Daniel Kirchner 2022-02-10 17:57:27 +01:00
parent e6848caac1
commit 9bcfcc61a7
6 changed files with 18 additions and 5 deletions

View File

@ -202,7 +202,7 @@ bool DocStringTagParser::visit(InlineAssembly const& _assembly)
if (valuesSeen.insert(value).second)
{
if (value == "memory-safe-assembly")
_assembly.annotation().memorySafe = true;
_assembly.annotation().markedMemorySafe = true;
else
m_errorReporter.warning(
8787_error,

View File

@ -763,6 +763,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType)
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
{
bool lvalueAccessToMemoryVariable = false;
// External references have already been resolved in a prior stage and stored in the annotation.
// We run the resolve step again regardless.
yul::ExternalIdentifierAccess::Resolver identifierAccess = [&](
@ -787,6 +788,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
{
solAssert(var->type(), "Expected variable type!");
if (_context == yul::IdentifierContext::LValue && var->type()->dataStoredIn(DataLocation::Memory))
lvalueAccessToMemoryVariable = true;
if (var->immutable())
{
m_errorReporter.typeError(3773_error, nativeLocationOf(_identifier), "Assembly access to immutable variables is not supported.");
@ -974,8 +977,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
identifierAccess
);
if (!analyzer.analyze(_inlineAssembly.operations()))
return false;
return true;
solAssert(m_errorReporter.hasErrors());
_inlineAssembly.annotation().hasMemoryEffects =
lvalueAccessToMemoryVariable ||
(analyzer.sideEffects().memory != yul::SideEffects::None);
return false;
}
bool TypeChecker::visit(IfStatement const& _ifStatement)

View File

@ -221,7 +221,9 @@ struct InlineAssemblyAnnotation: StatementAnnotation
/// Information generated during analysis phase.
std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
/// True, if the assembly block was annotated to be memory-safe.
bool memorySafe = false;
bool markedMemorySafe = false;
/// True, if the assembly block involves any memory opcode or assigns to variables in memory.
SetOnce<bool> hasMemoryEffects;
};
struct BlockAnnotation: StatementAnnotation, ScopableAnnotation

View File

@ -2138,7 +2138,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
{
setLocation(_inlineAsm);
if (!_inlineAsm.annotation().memorySafe)
if (*_inlineAsm.annotation().hasMemoryEffects && !_inlineAsm.annotation().markedMemorySafe)
m_context.setMemoryUnsafeInlineAssemblySeen();
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};

View File

@ -316,6 +316,7 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
literalArguments = &f->literalArguments;
validateInstructions(_funCall);
m_sideEffects += f->sideEffects;
}
else if (m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
[&](Scope::Variable const&)

View File

@ -94,6 +94,8 @@ public:
void operator()(Leave const&) { }
void operator()(Block const& _block);
/// @returns the worst side effects encountered during analysis (including within defined functions).
SideEffects const& sideEffects() const { return m_sideEffects; }
private:
/// Visits the expression, expects that it evaluates to exactly one value and
/// returns the type. Reports errors on errors and returns the default type.
@ -128,6 +130,8 @@ private:
/// Names of data objects to be referenced by builtin functions with literal arguments.
std::set<YulString> m_dataNames;
ForLoop const* m_currentForLoop = nullptr;
/// Worst side effects encountered during analysis (including within defined functions).
SideEffects m_sideEffects;
};
}