mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Inline assembly without memory effects is implicitly memory safe.
This commit is contained in:
parent
e6848caac1
commit
9bcfcc61a7
@ -202,7 +202,7 @@ bool DocStringTagParser::visit(InlineAssembly const& _assembly)
|
|||||||
if (valuesSeen.insert(value).second)
|
if (valuesSeen.insert(value).second)
|
||||||
{
|
{
|
||||||
if (value == "memory-safe-assembly")
|
if (value == "memory-safe-assembly")
|
||||||
_assembly.annotation().memorySafe = true;
|
_assembly.annotation().markedMemorySafe = true;
|
||||||
else
|
else
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
8787_error,
|
8787_error,
|
||||||
|
@ -763,6 +763,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType)
|
|||||||
|
|
||||||
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||||
{
|
{
|
||||||
|
bool lvalueAccessToMemoryVariable = false;
|
||||||
// External references have already been resolved in a prior stage and stored in the annotation.
|
// External references have already been resolved in a prior stage and stored in the annotation.
|
||||||
// We run the resolve step again regardless.
|
// We run the resolve step again regardless.
|
||||||
yul::ExternalIdentifierAccess::Resolver identifierAccess = [&](
|
yul::ExternalIdentifierAccess::Resolver identifierAccess = [&](
|
||||||
@ -787,6 +788,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
|
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
{
|
{
|
||||||
solAssert(var->type(), "Expected variable type!");
|
solAssert(var->type(), "Expected variable type!");
|
||||||
|
if (_context == yul::IdentifierContext::LValue && var->type()->dataStoredIn(DataLocation::Memory))
|
||||||
|
lvalueAccessToMemoryVariable = true;
|
||||||
if (var->immutable())
|
if (var->immutable())
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(3773_error, nativeLocationOf(_identifier), "Assembly access to immutable variables is not supported.");
|
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
|
identifierAccess
|
||||||
);
|
);
|
||||||
if (!analyzer.analyze(_inlineAssembly.operations()))
|
if (!analyzer.analyze(_inlineAssembly.operations()))
|
||||||
return false;
|
solAssert(m_errorReporter.hasErrors());
|
||||||
return true;
|
_inlineAssembly.annotation().hasMemoryEffects =
|
||||||
|
lvalueAccessToMemoryVariable ||
|
||||||
|
(analyzer.sideEffects().memory != yul::SideEffects::None);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeChecker::visit(IfStatement const& _ifStatement)
|
bool TypeChecker::visit(IfStatement const& _ifStatement)
|
||||||
|
@ -221,7 +221,9 @@ struct InlineAssemblyAnnotation: StatementAnnotation
|
|||||||
/// Information generated during analysis phase.
|
/// Information generated during analysis phase.
|
||||||
std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
|
std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
|
||||||
/// True, if the assembly block was annotated to be memory-safe.
|
/// 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
|
struct BlockAnnotation: StatementAnnotation, ScopableAnnotation
|
||||||
|
@ -2138,7 +2138,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
||||||
{
|
{
|
||||||
setLocation(_inlineAsm);
|
setLocation(_inlineAsm);
|
||||||
if (!_inlineAsm.annotation().memorySafe)
|
if (*_inlineAsm.annotation().hasMemoryEffects && !_inlineAsm.annotation().markedMemorySafe)
|
||||||
m_context.setMemoryUnsafeInlineAssemblySeen();
|
m_context.setMemoryUnsafeInlineAssemblySeen();
|
||||||
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};
|
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};
|
||||||
|
|
||||||
|
@ -316,6 +316,7 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
|||||||
literalArguments = &f->literalArguments;
|
literalArguments = &f->literalArguments;
|
||||||
|
|
||||||
validateInstructions(_funCall);
|
validateInstructions(_funCall);
|
||||||
|
m_sideEffects += f->sideEffects;
|
||||||
}
|
}
|
||||||
else if (m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
|
else if (m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
|
||||||
[&](Scope::Variable const&)
|
[&](Scope::Variable const&)
|
||||||
|
@ -94,6 +94,8 @@ public:
|
|||||||
void operator()(Leave const&) { }
|
void operator()(Leave const&) { }
|
||||||
void operator()(Block const& _block);
|
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:
|
private:
|
||||||
/// Visits the expression, expects that it evaluates to exactly one value and
|
/// Visits the expression, expects that it evaluates to exactly one value and
|
||||||
/// returns the type. Reports errors on errors and returns the default type.
|
/// 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.
|
/// Names of data objects to be referenced by builtin functions with literal arguments.
|
||||||
std::set<YulString> m_dataNames;
|
std::set<YulString> m_dataNames;
|
||||||
ForLoop const* m_currentForLoop = nullptr;
|
ForLoop const* m_currentForLoop = nullptr;
|
||||||
|
/// Worst side effects encountered during analysis (including within defined functions).
|
||||||
|
SideEffects m_sideEffects;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user