mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Allow annotating inline assembly as memory-safe.
This commit is contained in:
parent
e8520a667b
commit
e6848caac1
@ -1,6 +1,7 @@
|
|||||||
### 0.8.13 (unreleased)
|
### 0.8.13 (unreleased)
|
||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
|
* General: Allow annotating inline assembly as memory-safe to allow optimizations and stack limit evasion that rely on respecting Solidity's memory model.
|
||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <liblangutil/Common.h>
|
#include <liblangutil/Common.h>
|
||||||
|
|
||||||
#include <range/v3/algorithm/any_of.hpp>
|
#include <range/v3/algorithm/any_of.hpp>
|
||||||
|
#include <range/v3/view/filter.hpp>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
@ -162,6 +163,71 @@ bool DocStringTagParser::visit(ErrorDefinition const& _error)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DocStringTagParser::visit(InlineAssembly const& _assembly)
|
||||||
|
{
|
||||||
|
if (!_assembly.documentation())
|
||||||
|
return true;
|
||||||
|
StructuredDocumentation documentation{-1, _assembly.location(), _assembly.documentation()};
|
||||||
|
ErrorList errors;
|
||||||
|
ErrorReporter errorReporter{errors};
|
||||||
|
auto docTags = DocStringParser{documentation, errorReporter}.parse();
|
||||||
|
|
||||||
|
if (!errors.empty())
|
||||||
|
{
|
||||||
|
SecondarySourceLocation ssl;
|
||||||
|
for (auto const& error: errors)
|
||||||
|
if (error->comment())
|
||||||
|
ssl.append(
|
||||||
|
*error->comment(),
|
||||||
|
_assembly.location()
|
||||||
|
);
|
||||||
|
m_errorReporter.warning(
|
||||||
|
7828_error,
|
||||||
|
_assembly.location(),
|
||||||
|
"Inline assembly has invalid NatSpec documentation.",
|
||||||
|
ssl
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& [tagName, tagValue]: docTags)
|
||||||
|
{
|
||||||
|
if (tagName == "solidity")
|
||||||
|
{
|
||||||
|
vector<string> values;
|
||||||
|
boost::split(values, tagValue.content, isWhiteSpace);
|
||||||
|
|
||||||
|
set<string> valuesSeen;
|
||||||
|
set<string> duplicates;
|
||||||
|
for (auto const& value: values | ranges::views::filter(not_fn(&string::empty)))
|
||||||
|
if (valuesSeen.insert(value).second)
|
||||||
|
{
|
||||||
|
if (value == "memory-safe-assembly")
|
||||||
|
_assembly.annotation().memorySafe = true;
|
||||||
|
else
|
||||||
|
m_errorReporter.warning(
|
||||||
|
8787_error,
|
||||||
|
_assembly.location(),
|
||||||
|
"Unexpected value for @solidity tag in inline assembly: " + value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (duplicates.insert(value).second)
|
||||||
|
m_errorReporter.warning(
|
||||||
|
4377_error,
|
||||||
|
_assembly.location(),
|
||||||
|
"Value for @solidity tag in inline assembly specified multiple times: " + value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_errorReporter.warning(
|
||||||
|
6269_error,
|
||||||
|
_assembly.location(),
|
||||||
|
"Unexpected NatSpec tag \"" + tagName + "\" with value \"" + tagValue.content + "\" in inline assembly."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void DocStringTagParser::checkParameters(
|
void DocStringTagParser::checkParameters(
|
||||||
CallableDeclaration const& _callable,
|
CallableDeclaration const& _callable,
|
||||||
StructurallyDocumented const& _node,
|
StructurallyDocumented const& _node,
|
||||||
|
@ -48,6 +48,7 @@ private:
|
|||||||
bool visit(ModifierDefinition const& _modifier) override;
|
bool visit(ModifierDefinition const& _modifier) override;
|
||||||
bool visit(EventDefinition const& _event) override;
|
bool visit(EventDefinition const& _event) override;
|
||||||
bool visit(ErrorDefinition const& _error) override;
|
bool visit(ErrorDefinition const& _error) override;
|
||||||
|
bool visit(InlineAssembly const& _assembly) override;
|
||||||
|
|
||||||
void checkParameters(
|
void checkParameters(
|
||||||
CallableDeclaration const& _callable,
|
CallableDeclaration const& _callable,
|
||||||
|
@ -220,6 +220,8 @@ struct InlineAssemblyAnnotation: StatementAnnotation
|
|||||||
std::map<yul::Identifier const*, ExternalIdentifierInfo> externalReferences;
|
std::map<yul::Identifier const*, ExternalIdentifierInfo> externalReferences;
|
||||||
/// 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.
|
||||||
|
bool memorySafe = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BlockAnnotation: StatementAnnotation, ScopableAnnotation
|
struct BlockAnnotation: StatementAnnotation, ScopableAnnotation
|
||||||
|
@ -160,8 +160,8 @@ public:
|
|||||||
|
|
||||||
std::set<ContractDefinition const*, ASTNode::CompareByID>& subObjectsCreated() { return m_subObjects; }
|
std::set<ContractDefinition const*, ASTNode::CompareByID>& subObjectsCreated() { return m_subObjects; }
|
||||||
|
|
||||||
bool inlineAssemblySeen() const { return m_inlineAssemblySeen; }
|
bool memoryUnsafeInlineAssemblySeen() const { return m_memoryUnsafeInlineAssemblySeen; }
|
||||||
void setInlineAssemblySeen() { m_inlineAssemblySeen = true; }
|
void setMemoryUnsafeInlineAssemblySeen() { m_memoryUnsafeInlineAssemblySeen = true; }
|
||||||
|
|
||||||
/// @returns the runtime ID to be used for the function in the dispatch routine
|
/// @returns the runtime ID to be used for the function in the dispatch routine
|
||||||
/// and for internal function pointers.
|
/// and for internal function pointers.
|
||||||
@ -202,8 +202,8 @@ private:
|
|||||||
/// Whether to use checked or wrapping arithmetic.
|
/// Whether to use checked or wrapping arithmetic.
|
||||||
Arithmetic m_arithmetic = Arithmetic::Checked;
|
Arithmetic m_arithmetic = Arithmetic::Checked;
|
||||||
|
|
||||||
/// Flag indicating whether any inline assembly block was seen.
|
/// Flag indicating whether any memory-unsafe inline assembly block was seen.
|
||||||
bool m_inlineAssemblySeen = false;
|
bool m_memoryUnsafeInlineAssemblySeen = false;
|
||||||
|
|
||||||
/// Function definitions queued for code generation. They're the Solidity functions whose calls
|
/// Function definitions queued for code generation. They're the Solidity functions whose calls
|
||||||
/// were discovered by the IR generator during AST traversal.
|
/// were discovered by the IR generator during AST traversal.
|
||||||
|
@ -213,8 +213,8 @@ string IRGenerator::generate(
|
|||||||
t("subObjects", subObjectSources(m_context.subObjectsCreated()));
|
t("subObjects", subObjectSources(m_context.subObjectsCreated()));
|
||||||
|
|
||||||
// This has to be called only after all other code generation for the creation object is complete.
|
// This has to be called only after all other code generation for the creation object is complete.
|
||||||
bool creationInvolvesAssembly = m_context.inlineAssemblySeen();
|
bool creationInvolvesMemoryUnsafeAssembly = m_context.memoryUnsafeInlineAssemblySeen();
|
||||||
t("memoryInitCreation", memoryInit(!creationInvolvesAssembly));
|
t("memoryInitCreation", memoryInit(!creationInvolvesMemoryUnsafeAssembly));
|
||||||
t("useSrcMapCreation", formatUseSrcMap(m_context));
|
t("useSrcMapCreation", formatUseSrcMap(m_context));
|
||||||
|
|
||||||
resetContext(_contract, ExecutionContext::Deployed);
|
resetContext(_contract, ExecutionContext::Deployed);
|
||||||
@ -239,8 +239,8 @@ string IRGenerator::generate(
|
|||||||
t("useSrcMapDeployed", formatUseSrcMap(m_context));
|
t("useSrcMapDeployed", formatUseSrcMap(m_context));
|
||||||
|
|
||||||
// This has to be called only after all other code generation for the deployed object is complete.
|
// This has to be called only after all other code generation for the deployed object is complete.
|
||||||
bool deployedInvolvesAssembly = m_context.inlineAssemblySeen();
|
bool deployedInvolvesMemoryUnsafeAssembly = m_context.memoryUnsafeInlineAssemblySeen();
|
||||||
t("memoryInitDeployed", memoryInit(!deployedInvolvesAssembly));
|
t("memoryInitDeployed", memoryInit(!deployedInvolvesMemoryUnsafeAssembly));
|
||||||
|
|
||||||
solAssert(_contract.annotation().creationCallGraph->get() != nullptr, "");
|
solAssert(_contract.annotation().creationCallGraph->get() != nullptr, "");
|
||||||
solAssert(_contract.annotation().deployedCallGraph->get() != nullptr, "");
|
solAssert(_contract.annotation().deployedCallGraph->get() != nullptr, "");
|
||||||
|
@ -2138,7 +2138,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
|
||||||
{
|
{
|
||||||
setLocation(_inlineAsm);
|
setLocation(_inlineAsm);
|
||||||
m_context.setInlineAssemblySeen();
|
if (!_inlineAsm.annotation().memorySafe)
|
||||||
|
m_context.setMemoryUnsafeInlineAssemblySeen();
|
||||||
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};
|
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};
|
||||||
|
|
||||||
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
yul::Statement modified = bodyCopier(_inlineAsm.operations());
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
/// @test test
|
||||||
|
assembly {}
|
||||||
|
/// @solidity test
|
||||||
|
assembly {}
|
||||||
|
/// @param
|
||||||
|
assembly {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning 6269: (60-71): Unexpected natspec tag in inline assembly: test
|
||||||
|
// Warning 8787: (95-106): Unexpected value for @solidity tag in inline assembly: test
|
||||||
|
// Warning 7828: (122-133): Inline assembly has invalid natspec documentation.
|
@ -0,0 +1,6 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
// @solidity memory-safe-assembly
|
||||||
|
assembly {}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user