mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add exception for stack too deep error and binop stmt
This commit is contained in:
parent
9bfab1fe00
commit
3db10b8f69
@ -38,6 +38,7 @@ class Error;
|
|||||||
using ErrorList = std::vector<std::shared_ptr<Error const>>;
|
using ErrorList = std::vector<std::shared_ptr<Error const>>;
|
||||||
|
|
||||||
struct FuzzerError: virtual util::Exception {};
|
struct FuzzerError: virtual util::Exception {};
|
||||||
|
struct StackTooDeepError: virtual util::Exception {};
|
||||||
struct CompilerError: virtual util::Exception {};
|
struct CompilerError: virtual util::Exception {};
|
||||||
struct InternalCompilerError: virtual util::Exception {};
|
struct InternalCompilerError: virtual util::Exception {};
|
||||||
struct FatalError: virtual util::Exception {};
|
struct FatalError: virtual util::Exception {};
|
||||||
|
@ -219,8 +219,9 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
else
|
else
|
||||||
solUnimplemented("Copying of type " + _sourceType.toString(false) + " to storage not yet supported.");
|
solUnimplemented("Copying of type " + _sourceType.toString(false) + " to storage not yet supported.");
|
||||||
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] <source_value>...
|
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] <source_value>...
|
||||||
solAssert(
|
assertThrow(
|
||||||
2 + byteOffsetSize + sourceBaseType->sizeOnStack() <= 16,
|
2 + byteOffsetSize + sourceBaseType->sizeOnStack() <= 16,
|
||||||
|
StackTooDeepError,
|
||||||
"Stack too deep, try removing local variables."
|
"Stack too deep, try removing local variables."
|
||||||
);
|
);
|
||||||
// fetch target storage reference
|
// fetch target storage reference
|
||||||
|
@ -402,7 +402,7 @@ void CompilerContext::appendInlineAssembly(
|
|||||||
stackDiff -= 1;
|
stackDiff -= 1;
|
||||||
if (stackDiff < 1 || stackDiff > 16)
|
if (stackDiff < 1 || stackDiff > 16)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_identifier.location) <<
|
errinfo_sourceLocation(_identifier.location) <<
|
||||||
util::errinfo_comment("Stack too deep (" + to_string(stackDiff) + "), try removing local variables.")
|
util::errinfo_comment("Stack too deep (" + to_string(stackDiff) + "), try removing local variables.")
|
||||||
);
|
);
|
||||||
|
@ -455,7 +455,11 @@ void CompilerUtils::encodeToMemory(
|
|||||||
// leave end_of_mem as dyn head pointer
|
// leave end_of_mem as dyn head pointer
|
||||||
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
||||||
dynPointers++;
|
dynPointers++;
|
||||||
solAssert((argSize + dynPointers) < 16, "Stack too deep, try using fewer variables.");
|
assertThrow(
|
||||||
|
(argSize + dynPointers) < 16,
|
||||||
|
StackTooDeepError,
|
||||||
|
"Stack too deep, try using fewer variables."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -497,8 +501,9 @@ void CompilerUtils::encodeToMemory(
|
|||||||
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
|
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
|
||||||
{
|
{
|
||||||
// copy tail pointer (=mem_end - mem_start) to memory
|
// copy tail pointer (=mem_end - mem_start) to memory
|
||||||
solAssert(
|
assertThrow(
|
||||||
(2 + dynPointers) <= 16,
|
(2 + dynPointers) <= 16,
|
||||||
|
StackTooDeepError,
|
||||||
"Stack too deep(" + to_string(2 + dynPointers) + "), try using fewer variables."
|
"Stack too deep(" + to_string(2 + dynPointers) + "), try using fewer variables."
|
||||||
);
|
);
|
||||||
m_context << dupInstruction(2 + dynPointers) << Instruction::DUP2;
|
m_context << dupInstruction(2 + dynPointers) << Instruction::DUP2;
|
||||||
@ -1241,7 +1246,7 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
|
|||||||
// move variable starting from its top end in the stack
|
// move variable starting from its top end in the stack
|
||||||
if (stackPosition - size + 1 > 16)
|
if (stackPosition - size + 1 > 16)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_variable.location()) <<
|
errinfo_sourceLocation(_variable.location()) <<
|
||||||
util::errinfo_comment("Stack too deep, try removing local variables.")
|
util::errinfo_comment("Stack too deep, try removing local variables.")
|
||||||
);
|
);
|
||||||
@ -1251,7 +1256,11 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
|
|||||||
|
|
||||||
void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
||||||
{
|
{
|
||||||
solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables.");
|
assertThrow(
|
||||||
|
_stackDepth <= 16,
|
||||||
|
StackTooDeepError,
|
||||||
|
"Stack too deep, try removing local variables."
|
||||||
|
);
|
||||||
for (unsigned i = 0; i < _itemSize; ++i)
|
for (unsigned i = 0; i < _itemSize; ++i)
|
||||||
m_context << dupInstruction(_stackDepth);
|
m_context << dupInstruction(_stackDepth);
|
||||||
}
|
}
|
||||||
@ -1273,14 +1282,22 @@ void CompilerUtils::moveIntoStack(unsigned _stackDepth, unsigned _itemSize)
|
|||||||
|
|
||||||
void CompilerUtils::rotateStackUp(unsigned _items)
|
void CompilerUtils::rotateStackUp(unsigned _items)
|
||||||
{
|
{
|
||||||
solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables.");
|
assertThrow(
|
||||||
|
_items - 1 <= 16,
|
||||||
|
StackTooDeepError,
|
||||||
|
"Stack too deep, try removing local variables."
|
||||||
|
);
|
||||||
for (unsigned i = 1; i < _items; ++i)
|
for (unsigned i = 1; i < _items; ++i)
|
||||||
m_context << swapInstruction(_items - i);
|
m_context << swapInstruction(_items - i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::rotateStackDown(unsigned _items)
|
void CompilerUtils::rotateStackDown(unsigned _items)
|
||||||
{
|
{
|
||||||
solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables.");
|
assertThrow(
|
||||||
|
_items - 1 <= 16,
|
||||||
|
StackTooDeepError,
|
||||||
|
"Stack too deep, try removing local variables."
|
||||||
|
);
|
||||||
for (unsigned i = 1; i < _items; ++i)
|
for (unsigned i = 1; i < _items; ++i)
|
||||||
m_context << swapInstruction(i);
|
m_context << swapInstruction(i);
|
||||||
}
|
}
|
||||||
|
@ -630,7 +630,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
|
|||||||
|
|
||||||
if (stackLayout.size() > 17)
|
if (stackLayout.size() > 17)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_function.location()) <<
|
errinfo_sourceLocation(_function.location()) <<
|
||||||
errinfo_comment("Stack too deep, try removing local variables.")
|
errinfo_comment("Stack too deep, try removing local variables.")
|
||||||
);
|
);
|
||||||
@ -794,7 +794,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
solAssert(variable->type()->sizeOnStack() == 1, "");
|
solAssert(variable->type()->sizeOnStack() == 1, "");
|
||||||
if (stackDiff < 1 || stackDiff > 16)
|
if (stackDiff < 1 || stackDiff > 16)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_inlineAssembly.location()) <<
|
errinfo_sourceLocation(_inlineAssembly.location()) <<
|
||||||
errinfo_comment("Stack too deep, try removing local variables.")
|
errinfo_comment("Stack too deep, try removing local variables.")
|
||||||
);
|
);
|
||||||
@ -827,7 +827,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
|
|||||||
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable) - 1;
|
int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable) - 1;
|
||||||
if (stackDiff > 16 || stackDiff < 1)
|
if (stackDiff > 16 || stackDiff < 1)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_inlineAssembly.location()) <<
|
errinfo_sourceLocation(_inlineAssembly.location()) <<
|
||||||
errinfo_comment("Stack too deep(" + to_string(stackDiff) + "), try removing local variables.")
|
errinfo_comment("Stack too deep(" + to_string(stackDiff) + "), try removing local variables.")
|
||||||
);
|
);
|
||||||
|
@ -227,7 +227,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
solAssert(retSizeOnStack == utils().sizeOnStack(returnTypes), "");
|
solAssert(retSizeOnStack == utils().sizeOnStack(returnTypes), "");
|
||||||
if (retSizeOnStack > 15)
|
if (retSizeOnStack > 15)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_varDecl.location()) <<
|
errinfo_sourceLocation(_varDecl.location()) <<
|
||||||
errinfo_comment("Stack too deep.")
|
errinfo_comment("Stack too deep.")
|
||||||
);
|
);
|
||||||
@ -309,7 +309,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
|
|||||||
{
|
{
|
||||||
if (itemSize + lvalueSize > 16)
|
if (itemSize + lvalueSize > 16)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_assignment.location()) <<
|
errinfo_sourceLocation(_assignment.location()) <<
|
||||||
errinfo_comment("Stack too deep, try removing local variables.")
|
errinfo_comment("Stack too deep, try removing local variables.")
|
||||||
);
|
);
|
||||||
|
@ -47,7 +47,7 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const
|
|||||||
unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset);
|
unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset);
|
||||||
if (stackPos + 1 > 16) //@todo correct this by fetching earlier or moving to memory
|
if (stackPos + 1 > 16) //@todo correct this by fetching earlier or moving to memory
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_location) <<
|
errinfo_sourceLocation(_location) <<
|
||||||
errinfo_comment("Stack too deep, try removing local variables.")
|
errinfo_comment("Stack too deep, try removing local variables.")
|
||||||
);
|
);
|
||||||
@ -61,7 +61,7 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo
|
|||||||
unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1;
|
unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1;
|
||||||
if (stackDiff > 16)
|
if (stackDiff > 16)
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
CompilerError() <<
|
StackTooDeepError() <<
|
||||||
errinfo_sourceLocation(_location) <<
|
errinfo_sourceLocation(_location) <<
|
||||||
errinfo_comment("Stack too deep, try removing local variables.")
|
errinfo_comment("Stack too deep, try removing local variables.")
|
||||||
);
|
);
|
||||||
|
@ -98,13 +98,13 @@ message Statement {
|
|||||||
VarDecl vd = 1;
|
VarDecl vd = 1;
|
||||||
Assignment a = 2;
|
Assignment a = 2;
|
||||||
UnaryOpStmt u = 3;
|
UnaryOpStmt u = 3;
|
||||||
|
BinaryOpStmt b = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Block {
|
message Block {
|
||||||
required VarDecl v = 1;
|
repeated Statement s = 1;
|
||||||
repeated Statement s = 2;
|
required Return r = 2;
|
||||||
required Return r = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message Program {
|
message Program {
|
||||||
|
@ -123,7 +123,7 @@ std::pair<bytes, Json::Value> compileContract(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Ignore stack too deep errors during compilation
|
// Ignore stack too deep errors during compilation
|
||||||
catch (Exception const&)
|
catch (langutil::StackTooDeepError const&)
|
||||||
{
|
{
|
||||||
throw langutil::FuzzerError();
|
throw langutil::FuzzerError();
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ string ProtoConverter::visit(Block const& _block)
|
|||||||
<< '\t'
|
<< '\t'
|
||||||
<< '{'
|
<< '{'
|
||||||
<< '\n';
|
<< '\n';
|
||||||
blockStr << visit(_block.v());
|
|
||||||
for (auto const& s: _block.s())
|
for (auto const& s: _block.s())
|
||||||
blockStr << visit(s);
|
blockStr << visit(s);
|
||||||
blockStr << visit(_block.r());
|
blockStr << visit(_block.r());
|
||||||
@ -67,9 +66,20 @@ string ProtoConverter::visit(Statement const& _stmt)
|
|||||||
case Statement::kVd:
|
case Statement::kVd:
|
||||||
return visit(_stmt.vd());
|
return visit(_stmt.vd());
|
||||||
case Statement::kA:
|
case Statement::kA:
|
||||||
return visit(_stmt.a());
|
if (varAvailable())
|
||||||
|
return visit(_stmt.a());
|
||||||
|
else
|
||||||
|
return "";
|
||||||
case Statement::kU:
|
case Statement::kU:
|
||||||
return visit(_stmt.u());
|
if (varAvailable())
|
||||||
|
return visit(_stmt.u());
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
case Statement::kB:
|
||||||
|
if (varAvailable())
|
||||||
|
return visit(_stmt.b());
|
||||||
|
else
|
||||||
|
return "";
|
||||||
case Statement::STMT_ONEOF_NOT_SET:
|
case Statement::STMT_ONEOF_NOT_SET:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -77,14 +87,13 @@ string ProtoConverter::visit(Statement const& _stmt)
|
|||||||
|
|
||||||
string ProtoConverter::visit(VarDecl const& _vardecl)
|
string ProtoConverter::visit(VarDecl const& _vardecl)
|
||||||
{
|
{
|
||||||
bool varExists = varAvailable();
|
|
||||||
Whiskers v(R"(<type> <varName> = <type>(<value>);)");
|
Whiskers v(R"(<type> <varName> = <type>(<value>);)");
|
||||||
string type = visit(_vardecl.t());
|
string type = visit(_vardecl.t());
|
||||||
string varName = newVarName();
|
string varName = newVarName();
|
||||||
m_varTypeMap.emplace(varName, pair(typeSign(_vardecl.t()), type));
|
m_varTypeMap.emplace(varName, pair(typeSign(_vardecl.t()), type));
|
||||||
v("type", type);
|
v("type", type);
|
||||||
v("varName", varName);
|
v("varName", varName);
|
||||||
v("value", varExists ? visit(_vardecl.value()) : maskUnsignedToHex(64));
|
v("value", visit(_vardecl.value()));
|
||||||
incrementVarCounter();
|
incrementVarCounter();
|
||||||
return "\t\t" + v.render() + '\n';
|
return "\t\t" + v.render() + '\n';
|
||||||
}
|
}
|
||||||
@ -109,6 +118,43 @@ string ProtoConverter::visit(UnaryOpStmt const& _uop)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string ProtoConverter::visit(BinaryOpStmt const& _bopstmt)
|
||||||
|
{
|
||||||
|
string op{};
|
||||||
|
switch (_bopstmt.op())
|
||||||
|
{
|
||||||
|
case BinaryOpStmt::ADDSELF:
|
||||||
|
op = " += ";
|
||||||
|
break;
|
||||||
|
case BinaryOpStmt::SUBSELF:
|
||||||
|
op = " -= ";
|
||||||
|
break;
|
||||||
|
case BinaryOpStmt::MULSELF:
|
||||||
|
op = " *= ";
|
||||||
|
break;
|
||||||
|
case BinaryOpStmt::DIVSELF:
|
||||||
|
op = " /= ";
|
||||||
|
break;
|
||||||
|
case BinaryOpStmt::MODSELF:
|
||||||
|
op = " %= ";
|
||||||
|
break;
|
||||||
|
case BinaryOpStmt::SHLSELF:
|
||||||
|
op = " <<= ";
|
||||||
|
break;
|
||||||
|
case BinaryOpStmt::SHRSELF:
|
||||||
|
op = " >>= ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
string left = visit(_bopstmt.left());
|
||||||
|
string right = visit(_bopstmt.right());
|
||||||
|
|
||||||
|
string leftSignString = m_varTypeMap[left].second;
|
||||||
|
string rightSignString = m_exprSignMap[&_bopstmt.right()].second;
|
||||||
|
if (leftSignString != rightSignString)
|
||||||
|
right = leftSignString + '(' + right + ')';
|
||||||
|
return "\t\t" + left + op + right + ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
string ProtoConverter::visit(BinaryOp const& _bop)
|
string ProtoConverter::visit(BinaryOp const& _bop)
|
||||||
{
|
{
|
||||||
string op{};
|
string op{};
|
||||||
@ -163,11 +209,19 @@ string ProtoConverter::visit(Expression const& _expr)
|
|||||||
{
|
{
|
||||||
case Expression::kV:
|
case Expression::kV:
|
||||||
{
|
{
|
||||||
solAssert(varAvailable(), "Sol arith fuzzer: Varref unavaileble");
|
if (varAvailable())
|
||||||
string v = visit(_expr.v());
|
{
|
||||||
if (!m_exprSignMap.count(&_expr))
|
string v = visit(_expr.v());
|
||||||
m_exprSignMap.emplace(&_expr, m_varTypeMap[v]);
|
if (!m_exprSignMap.count(&_expr))
|
||||||
return v;
|
m_exprSignMap.emplace(&_expr, m_varTypeMap[v]);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!m_exprSignMap.count(&_expr))
|
||||||
|
m_exprSignMap.emplace(&_expr, pair(Sign::Unsigned, "uint"));
|
||||||
|
return maskUnsignedToHex(64);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case Expression::kBop:
|
case Expression::kBop:
|
||||||
{
|
{
|
||||||
@ -193,16 +247,11 @@ string ProtoConverter::visit(VarRef const& _v)
|
|||||||
|
|
||||||
string ProtoConverter::visit(Assignment const& _assignment)
|
string ProtoConverter::visit(Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
if (varAvailable())
|
string varName = visit(_assignment.id());
|
||||||
{
|
solAssert(m_varTypeMap.count(varName), "Sol arith fuzzer: Invalid varname");
|
||||||
string varName = visit(_assignment.id());
|
Whiskers a(R"(<varName> = <type>(<expr>);)");
|
||||||
solAssert(m_varTypeMap.count(varName), "Sol arith fuzzer: Invalid varname");
|
a("varName", varName);
|
||||||
Whiskers a(R"(<varName> = <type>(<expr>);)");
|
a("type", m_varTypeMap[varName].second);
|
||||||
a("varName", varName);
|
a("expr", visit(_assignment.value()));
|
||||||
a("type", m_varTypeMap[varName].second);
|
return "\t\t" + a.render() + '\n';
|
||||||
a("expr", visit(_assignment.value()));
|
|
||||||
return "\t\t" + a.render() + '\n';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
}
|
@ -70,6 +70,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::string visit(Type const& _type);
|
std::string visit(Type const& _type);
|
||||||
std::string visit(UnaryOpStmt const& _uop);
|
std::string visit(UnaryOpStmt const& _uop);
|
||||||
|
std::string visit(BinaryOpStmt const& _bop);
|
||||||
std::string visit(BinaryOp const& _bop);
|
std::string visit(BinaryOp const& _bop);
|
||||||
std::string visit(VarDecl const& _decl);
|
std::string visit(VarDecl const& _decl);
|
||||||
std::string visit(Assignment const& _assignment);
|
std::string visit(Assignment const& _assignment);
|
||||||
|
Loading…
Reference in New Issue
Block a user