mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Better error message for out of stack in assembly.
This commit is contained in:
parent
d6b8521ed5
commit
17a1e7aed5
@ -184,14 +184,25 @@ void CodeGenerator::assemble(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
EthAssemblyAdapter assemblyAdapter(_assembly);
|
EthAssemblyAdapter assemblyAdapter(_assembly);
|
||||||
CodeTransform(
|
try
|
||||||
assemblyAdapter,
|
{
|
||||||
_analysisInfo,
|
CodeTransform(
|
||||||
_parsedData,
|
assemblyAdapter,
|
||||||
*EVMDialect::strictAssemblyForEVM(),
|
_analysisInfo,
|
||||||
_optimize,
|
_parsedData,
|
||||||
false,
|
*EVMDialect::strictAssemblyForEVM(),
|
||||||
_identifierAccess,
|
_optimize,
|
||||||
_useNamedLabelsForFunctions
|
false,
|
||||||
)(_parsedData);
|
_identifierAccess,
|
||||||
|
_useNamedLabelsForFunctions
|
||||||
|
)(_parsedData);
|
||||||
|
}
|
||||||
|
catch (StackTooDeepError const& _e)
|
||||||
|
{
|
||||||
|
BOOST_THROW_EXCEPTION(
|
||||||
|
InternalCompilerError() << errinfo_comment(
|
||||||
|
"Stack too deep when compiling inline assembly" +
|
||||||
|
(_e.comment() ? ": " + *_e.comment() : ".")
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,8 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
bool atTopOfStack = true;
|
bool atTopOfStack = true;
|
||||||
for (int varIndex = numVariables - 1; varIndex >= 0; --varIndex)
|
for (int varIndex = numVariables - 1; varIndex >= 0; --varIndex)
|
||||||
{
|
{
|
||||||
auto& var = boost::get<Scope::Variable>(m_scope->identifiers.at(_varDecl.variables[varIndex].name));
|
YulString varName = _varDecl.variables[varIndex].name;
|
||||||
|
auto& var = boost::get<Scope::Variable>(m_scope->identifiers.at(varName));
|
||||||
m_context->variableStackHeights[&var] = height + varIndex;
|
m_context->variableStackHeights[&var] = height + varIndex;
|
||||||
if (!m_allowStackOpt)
|
if (!m_allowStackOpt)
|
||||||
continue;
|
continue;
|
||||||
@ -217,7 +218,7 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
|||||||
m_unusedStackSlots.erase(m_unusedStackSlots.begin());
|
m_unusedStackSlots.erase(m_unusedStackSlots.begin());
|
||||||
m_context->variableStackHeights[&var] = slot;
|
m_context->variableStackHeights[&var] = slot;
|
||||||
m_assembly.setSourceLocation(_varDecl.location);
|
m_assembly.setSourceLocation(_varDecl.location);
|
||||||
if (int heightDiff = variableHeightDiff(var, true))
|
if (int heightDiff = variableHeightDiff(var, varName, true))
|
||||||
m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1));
|
m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1));
|
||||||
m_assembly.appendInstruction(solidity::Instruction::POP);
|
m_assembly.appendInstruction(solidity::Instruction::POP);
|
||||||
--m_stackAdjustment;
|
--m_stackAdjustment;
|
||||||
@ -353,7 +354,7 @@ void CodeTransform::operator()(Identifier const& _identifier)
|
|||||||
{
|
{
|
||||||
// TODO: opportunity for optimization: Do not DUP if this is the last reference
|
// TODO: opportunity for optimization: Do not DUP if this is the last reference
|
||||||
// to the top most element of the stack
|
// to the top most element of the stack
|
||||||
if (int heightDiff = variableHeightDiff(_var, false))
|
if (int heightDiff = variableHeightDiff(_var, _identifier.name, false))
|
||||||
m_assembly.appendInstruction(solidity::dupInstruction(heightDiff));
|
m_assembly.appendInstruction(solidity::dupInstruction(heightDiff));
|
||||||
else
|
else
|
||||||
// Store something to balance the stack
|
// Store something to balance the stack
|
||||||
@ -542,7 +543,14 @@ void CodeTransform::operator()(FunctionDefinition const& _function)
|
|||||||
for (size_t i = 0; i < _function.returnVariables.size(); ++i)
|
for (size_t i = 0; i < _function.returnVariables.size(); ++i)
|
||||||
stackLayout.push_back(i); // Move return values down, but keep order.
|
stackLayout.push_back(i); // Move return values down, but keep order.
|
||||||
|
|
||||||
solAssert(stackLayout.size() <= 17, "Stack too deep");
|
if (stackLayout.size() > 17)
|
||||||
|
BOOST_THROW_EXCEPTION(StackTooDeepError() << errinfo_comment(
|
||||||
|
"The function " +
|
||||||
|
_function.name.str() +
|
||||||
|
" has " +
|
||||||
|
to_string(stackLayout.size() - 17) +
|
||||||
|
" parameters or return variables too many to fit the stack size."
|
||||||
|
));
|
||||||
while (!stackLayout.empty() && stackLayout.back() != int(stackLayout.size() - 1))
|
while (!stackLayout.empty() && stackLayout.back() != int(stackLayout.size() - 1))
|
||||||
if (stackLayout.back() < 0)
|
if (stackLayout.back() < 0)
|
||||||
{
|
{
|
||||||
@ -711,7 +719,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
|
|||||||
if (auto var = m_scope->lookup(_variableName.name))
|
if (auto var = m_scope->lookup(_variableName.name))
|
||||||
{
|
{
|
||||||
Scope::Variable const& _var = boost::get<Scope::Variable>(*var);
|
Scope::Variable const& _var = boost::get<Scope::Variable>(*var);
|
||||||
if (int heightDiff = variableHeightDiff(_var, true))
|
if (int heightDiff = variableHeightDiff(_var, _variableName.name, true))
|
||||||
m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1));
|
m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1));
|
||||||
m_assembly.appendInstruction(solidity::Instruction::POP);
|
m_assembly.appendInstruction(solidity::Instruction::POP);
|
||||||
decreaseReference(_variableName.name, _var);
|
decreaseReference(_variableName.name, _var);
|
||||||
@ -726,19 +734,21 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CodeTransform::variableHeightDiff(Scope::Variable const& _var, bool _forSwap) const
|
int CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString _varName, bool _forSwap) const
|
||||||
{
|
{
|
||||||
solAssert(m_context->variableStackHeights.count(&_var), "");
|
solAssert(m_context->variableStackHeights.count(&_var), "");
|
||||||
int heightDiff = m_assembly.stackHeight() - m_context->variableStackHeights[&_var];
|
int heightDiff = m_assembly.stackHeight() - m_context->variableStackHeights[&_var];
|
||||||
if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16))
|
solAssert(heightDiff > (_forSwap ? 1 : 0), "Negative stack difference for variable.");
|
||||||
{
|
int limit = _forSwap ? 17 : 16;
|
||||||
solUnimplemented(
|
if (heightDiff > limit)
|
||||||
"Variable inaccessible, too deep inside stack (" + to_string(heightDiff) + ")"
|
BOOST_THROW_EXCEPTION(StackTooDeepError() << errinfo_comment(
|
||||||
);
|
"Variable " +
|
||||||
return 0;
|
_varName.str() +
|
||||||
}
|
" is " +
|
||||||
else
|
to_string(heightDiff - limit) +
|
||||||
return heightDiff;
|
" slot(s) too deep inside the stack."
|
||||||
|
));
|
||||||
|
return heightDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeTransform::expectDeposit(int _deposit, int _oldHeight) const
|
void CodeTransform::expectDeposit(int _deposit, int _oldHeight) const
|
||||||
|
@ -40,6 +40,8 @@ namespace yul
|
|||||||
struct AsmAnalysisInfo;
|
struct AsmAnalysisInfo;
|
||||||
class EVMAssembly;
|
class EVMAssembly;
|
||||||
|
|
||||||
|
struct StackTooDeepError: virtual YulException {};
|
||||||
|
|
||||||
struct CodeTransformContext
|
struct CodeTransformContext
|
||||||
{
|
{
|
||||||
std::map<Scope::Label const*, AbstractAssembly::LabelID> labelIDs;
|
std::map<Scope::Label const*, AbstractAssembly::LabelID> labelIDs;
|
||||||
@ -85,6 +87,10 @@ class CodeTransform: public boost::static_visitor<>
|
|||||||
public:
|
public:
|
||||||
/// Create the code transformer.
|
/// Create the code transformer.
|
||||||
/// @param _identifierAccess used to resolve identifiers external to the inline assembly
|
/// @param _identifierAccess used to resolve identifiers external to the inline assembly
|
||||||
|
/// As a side-effect of its construction, translates the Yul code and appends it to the
|
||||||
|
/// given assembly.
|
||||||
|
/// Throws StackTooDeepError if a variable is not accessible or if a function has too
|
||||||
|
/// many parameters.
|
||||||
CodeTransform(
|
CodeTransform(
|
||||||
AbstractAssembly& _assembly,
|
AbstractAssembly& _assembly,
|
||||||
AsmAnalysisInfo& _analysisInfo,
|
AsmAnalysisInfo& _analysisInfo,
|
||||||
@ -172,7 +178,7 @@ private:
|
|||||||
/// Determines the stack height difference to the given variables. Throws
|
/// Determines the stack height difference to the given variables. Throws
|
||||||
/// if it is not yet in scope or the height difference is too large. Returns
|
/// if it is not yet in scope or the height difference is too large. Returns
|
||||||
/// the (positive) stack height difference otherwise.
|
/// the (positive) stack height difference otherwise.
|
||||||
int variableHeightDiff(Scope::Variable const& _var, bool _forSwap) const;
|
int variableHeightDiff(Scope::Variable const& _var, YulString _name, bool _forSwap) const;
|
||||||
|
|
||||||
void expectDeposit(int _deposit, int _oldHeight) const;
|
void expectDeposit(int _deposit, int _oldHeight) const;
|
||||||
|
|
||||||
|
@ -60,5 +60,7 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize)
|
|||||||
|
|
||||||
yulAssert(_object.analysisInfo, "No analysis info.");
|
yulAssert(_object.analysisInfo, "No analysis info.");
|
||||||
yulAssert(_object.code, "No code.");
|
yulAssert(_object.code, "No code.");
|
||||||
|
// We do not catch and re-throw the stack too deep exception here because it is a YulException,
|
||||||
|
// which should be native to this part of the code.
|
||||||
CodeTransform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, _optimize, m_evm15}(*_object.code);
|
CodeTransform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, _optimize, m_evm15}(*_object.code);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user