Skip to content

Commit

Permalink
f
Browse files Browse the repository at this point in the history
  • Loading branch information
clonker committed Aug 20, 2024
1 parent 5c0a6d9 commit b69030d
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 66 deletions.
152 changes: 86 additions & 66 deletions libyul/AsmAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,82 +293,102 @@ void AsmAnalyzer::operator()(FunctionDefinition const& _funDef)

size_t AsmAnalyzer::operator()(FunctionCall const& _funCall)
{
yulAssert(!_funCall.functionName.name.empty(), "");
auto watcher = m_errorReporter.errorWatcher();
std::optional<size_t> numParameters;
std::optional<size_t> numReturns;
std::vector<std::optional<LiteralKind>> const* literalArguments = nullptr;

if (BuiltinFunction const* f = m_dialect.builtin(_funCall.functionName.name))
{
if (_funCall.functionName.name == "selfdestruct"_yulname)
m_errorReporter.warning(
1699_error,
nativeLocationOf(_funCall.functionName),
"\"selfdestruct\" has been deprecated. "
"Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code and "
"data associated with an account and only transfers its Ether to the beneficiary, "
"unless executed in the same transaction in which the contract was created (see EIP-6780). "
"Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. "
"Future changes to the EVM might further reduce the functionality of the opcode."
);
else if (
m_evmVersion.supportsTransientStorage() &&
_funCall.functionName.name == "tstore"_yulname &&
!m_errorReporter.hasError({2394})
)
m_errorReporter.warning(
2394_error,
nativeLocationOf(_funCall.functionName),
"Transient storage as defined by EIP-1153 can break the composability of smart contracts: "
"Since transient storage is cleared only at the end of the transaction and not at the end of the outermost call frame to the contract within a transaction, "
"your contract may unintentionally misbehave when invoked multiple times in a complex transaction. "
"To avoid this, be sure to clear all transient storage at the end of any call to your contract. "
"The use of transient storage for reentrancy guards that are cleared at the end of the call is safe."
);
GenericVisitor visitor{
[&](Builtin const& _builtin)
{
auto const& function = m_dialect.builtinFunction(_builtin.handle);
yulAssert(!function.name.empty(), "");
if (function.name == "selfdestruct")
m_errorReporter.warning(
1699_error,
nativeLocationOf(_funCall.functionName),
"\"selfdestruct\" has been deprecated. "
"Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code and "
"data associated with an account and only transfers its Ether to the beneficiary, "
"unless executed in the same transaction in which the contract was created (see EIP-6780). "
"Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. "
"Future changes to the EVM might further reduce the functionality of the opcode."
);
else if (
m_evmVersion.supportsTransientStorage() &&
function.name == "tstore" &&
!m_errorReporter.hasError({2394})
)
m_errorReporter.warning(
2394_error,
nativeLocationOf(_funCall.functionName),
"Transient storage as defined by EIP-1153 can break the composability of smart contracts: "
"Since transient storage is cleared only at the end of the transaction and not at the end of the outermost call frame to the contract within a transaction, "
"your contract may unintentionally misbehave when invoked multiple times in a complex transaction. "
"To avoid this, be sure to clear all transient storage at the end of any call to your contract. "
"The use of transient storage for reentrancy guards that are cleared at the end of the call is safe."
);

numParameters = f->numParameters;
numReturns = f->numReturns;
if (!f->literalArguments.empty())
literalArguments = &f->literalArguments;
numParameters = function.numParameters;
numReturns = function.numReturns;
if (!function.literalArguments.empty())
literalArguments = &function.literalArguments;

validateInstructions(_funCall);
m_sideEffects += f->sideEffects;
}
else if (m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{
[&](Scope::Variable const&)
{
m_errorReporter.typeError(
4202_error,
nativeLocationOf(_funCall.functionName),
"Attempt to call variable instead of function."
);
validateInstructions(_funCall);
m_sideEffects += function.sideEffects;
},
[&](Scope::Function const& _fun)
[&](Verbatim const& _verbatim)
{
numParameters = _fun.numArguments;
numReturns = _fun.numReturns;
auto const& function = m_dialect.verbatimFunction(_verbatim.handle);
yulAssert(!function.name.empty(), "");
numParameters = function.numParameters;
numReturns = function.numReturns;
if (!function.literalArguments.empty())
literalArguments = &function.literalArguments;

validateInstructions(_funCall);
m_sideEffects += function.sideEffects;
},
[&](Identifier const& _identifier)
{
yulAssert(!_identifier.name.empty(), "");
if (m_currentScope->lookup(_identifier.name, GenericVisitor{
[&](Scope::Variable const&)
{
m_errorReporter.typeError(
4202_error,
nativeLocationOf(_funCall.functionName),
"Attempt to call variable instead of function."
);
},
[&](Scope::Function const& _fun)
{
numParameters = _fun.numArguments;
numReturns = _fun.numReturns;
}
}))
{
if (m_resolver)
// We found a local reference, make sure there is no external reference.
m_resolver(
_identifier,
yul::IdentifierContext::NonExternal,
m_currentScope->insideFunction()
);
}
else
{
if (!validateInstructions(_funCall))
m_errorReporter.declarationError(
4619_error,
nativeLocationOf(_funCall.functionName),
"Function \"" + _identifier.name.str() + "\" not found."
);
yulAssert(!watcher.ok(), "Expected a reported error.");
}
}
}))
{
if (m_resolver)
// We found a local reference, make sure there is no external reference.
m_resolver(
_funCall.functionName,
yul::IdentifierContext::NonExternal,
m_currentScope->insideFunction()
);
}
else
{
if (!validateInstructions(_funCall))
m_errorReporter.declarationError(
4619_error,
nativeLocationOf(_funCall.functionName),
"Function \"" + _funCall.functionName.name.str() + "\" not found."
);
yulAssert(!watcher.ok(), "Expected a reported error.");
}
};
std::visit(visitor, _funCall.functionName);

if (numParameters && _funCall.arguments.size() != *numParameters)
m_errorReporter.typeError(
Expand Down
4 changes: 4 additions & 0 deletions libyul/optimiser/ASTWalker.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class ASTWalker
virtual ~ASTWalker() = default;
virtual void operator()(Literal const&) {}
virtual void operator()(Identifier const&) {}
virtual void operator()(Builtin const&) {}
virtual void operator()(Verbatim const&) {}
virtual void operator()(FunctionCall const& _funCall);
virtual void operator()(ExpressionStatement const& _statement);
virtual void operator()(Assignment const& _assignment);
Expand Down Expand Up @@ -77,6 +79,8 @@ class ASTModifier
virtual ~ASTModifier() = default;
virtual void operator()(Literal&) {}
virtual void operator()(Identifier&) {}
virtual void operator()(Builtin&) {}
virtual void operator()(Verbatim&) {}
virtual void operator()(FunctionCall& _funCall);
virtual void operator()(ExpressionStatement& _statement);
virtual void operator()(Assignment& _assignment);
Expand Down

0 comments on commit b69030d

Please sign in to comment.