From 1a0391bceb81137b46b15b8c7f81004b6e99240e Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 1 Jul 2020 09:46:06 +0200 Subject: [PATCH] Fuzzer: Add a specialized StackTooDeepError Exception that is caught in the fuzzing harness --- liblangutil/Exceptions.h | 1 + libsolidity/codegen/ArrayUtils.cpp | 3 ++- libsolidity/codegen/CompilerContext.cpp | 2 +- libsolidity/codegen/CompilerUtils.cpp | 29 +++++++++++++++++----- libsolidity/codegen/ContractCompiler.cpp | 6 ++--- libsolidity/codegen/ExpressionCompiler.cpp | 4 +-- libsolidity/codegen/LValue.cpp | 4 +-- libyul/backends/evm/AsmCodeGen.cpp | 3 ++- test/libsolidity/StandardCompiler.cpp | 2 +- test/tools/fuzzer_common.cpp | 3 +++ 10 files changed, 40 insertions(+), 17 deletions(-) diff --git a/liblangutil/Exceptions.h b/liblangutil/Exceptions.h index 083a5e3cd..fef09cbfa 100644 --- a/liblangutil/Exceptions.h +++ b/liblangutil/Exceptions.h @@ -38,6 +38,7 @@ class Error; using ErrorList = std::vector>; struct CompilerError: virtual util::Exception {}; +struct StackTooDeepError: virtual CompilerError {}; struct InternalCompilerError: virtual util::Exception {}; struct FatalError: virtual util::Exception {}; struct UnimplementedFeatureError: virtual util::Exception {}; diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 9f12f648f..eebe03e53 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -226,8 +226,9 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons else 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] ... - solAssert( + assertThrow( 2 + byteOffsetSize + sourceBaseType->sizeOnStack() <= 16, + StackTooDeepError, "Stack too deep, try removing local variables." ); // fetch target storage reference diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 3af9a7c94..4a9b1918d 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -404,7 +404,7 @@ void CompilerContext::appendInlineAssembly( stackDiff -= 1; if (stackDiff < 1 || stackDiff > 16) BOOST_THROW_EXCEPTION( - CompilerError() << + StackTooDeepError() << errinfo_sourceLocation(_identifier.location) << util::errinfo_comment("Stack too deep (" + to_string(stackDiff) + "), try removing local variables.") ); diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index c3e81d13a..b3fc9da2e 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -455,7 +455,11 @@ void CompilerUtils::encodeToMemory( // leave end_of_mem as dyn head pointer m_context << Instruction::DUP1 << u256(32) << Instruction::ADD; 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 { @@ -507,8 +511,9 @@ void CompilerUtils::encodeToMemory( if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace) { // copy tail pointer (=mem_end - mem_start) to memory - solAssert( + assertThrow( (2 + dynPointers) <= 16, + StackTooDeepError, "Stack too deep(" + to_string(2 + dynPointers) + "), try using fewer variables." ); m_context << dupInstruction(2 + dynPointers) << Instruction::DUP2; @@ -1290,7 +1295,7 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) // move variable starting from its top end in the stack if (stackPosition - size + 1 > 16) BOOST_THROW_EXCEPTION( - CompilerError() << + StackTooDeepError() << errinfo_sourceLocation(_variable.location()) << util::errinfo_comment("Stack too deep, try removing local variables.") ); @@ -1300,7 +1305,11 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) 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) m_context << dupInstruction(_stackDepth); } @@ -1322,14 +1331,22 @@ void CompilerUtils::moveIntoStack(unsigned _stackDepth, unsigned _itemSize) 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) m_context << swapInstruction(_items - i); } 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) m_context << swapInstruction(i); } diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 6f8603a51..3d1b41e41 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -634,7 +634,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function) if (stackLayout.size() > 17) BOOST_THROW_EXCEPTION( - CompilerError() << + StackTooDeepError() << errinfo_sourceLocation(_function.location()) << errinfo_comment("Stack too deep, try removing local variables.") ); @@ -798,7 +798,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) solAssert(variable->type()->sizeOnStack() == 1, ""); if (stackDiff < 1 || stackDiff > 16) BOOST_THROW_EXCEPTION( - CompilerError() << + StackTooDeepError() << errinfo_sourceLocation(_inlineAssembly.location()) << errinfo_comment("Stack too deep, try removing local variables.") ); @@ -831,7 +831,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) unsigned stackDiff = static_cast(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable) - 1; if (stackDiff > 16 || stackDiff < 1) BOOST_THROW_EXCEPTION( - CompilerError() << + StackTooDeepError() << errinfo_sourceLocation(_inlineAssembly.location()) << errinfo_comment("Stack too deep(" + to_string(stackDiff) + "), try removing local variables.") ); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index cbacd0a7e..ffa8ced4c 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -226,7 +226,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& solAssert(retSizeOnStack == utils().sizeOnStack(returnTypes), ""); if (retSizeOnStack > 15) BOOST_THROW_EXCEPTION( - CompilerError() << + StackTooDeepError() << errinfo_sourceLocation(_varDecl.location()) << errinfo_comment("Stack too deep.") ); @@ -308,7 +308,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) { if (itemSize + lvalueSize > 16) BOOST_THROW_EXCEPTION( - CompilerError() << + StackTooDeepError() << errinfo_sourceLocation(_assignment.location()) << errinfo_comment("Stack too deep, try removing local variables.") ); diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 3a04d6f92..798428098 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -47,7 +47,7 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset); if (stackPos + 1 > 16) //@todo correct this by fetching earlier or moving to memory BOOST_THROW_EXCEPTION( - CompilerError() << + StackTooDeepError() << errinfo_sourceLocation(_location) << 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; if (stackDiff > 16) BOOST_THROW_EXCEPTION( - CompilerError() << + StackTooDeepError() << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep, try removing local variables.") ); diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index 6775214e8..5827f6524 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -218,8 +218,9 @@ void CodeGenerator::assemble( } catch (StackTooDeepError const& _e) { - yulAssert( + assertThrow( false, + langutil::StackTooDeepError, "Stack too deep when compiling inline assembly" + (_e.comment() ? ": " + *_e.comment() : ".") ); diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index e4f77b581..0b2098097 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -1242,7 +1242,7 @@ BOOST_AUTO_TEST_CASE(use_stack_optimization) BOOST_CHECK(result["errors"][0]["severity"] == "error"); BOOST_REQUIRE(result["errors"][0]["message"].isString()); BOOST_CHECK(result["errors"][0]["message"].asString().find("Stack too deep when compiling inline assembly") != std::string::npos); - BOOST_CHECK(result["errors"][0]["type"] == "YulException"); + BOOST_CHECK(result["errors"][0]["type"] == "CompilerError"); } BOOST_AUTO_TEST_CASE(standard_output_selection_wildcard) diff --git a/test/tools/fuzzer_common.cpp b/test/tools/fuzzer_common.cpp index fa167c437..ac2e13775 100644 --- a/test/tools/fuzzer_common.cpp +++ b/test/tools/fuzzer_common.cpp @@ -96,6 +96,9 @@ void FuzzerUtil::testCompiler(string const& _input, bool _optimize) catch (UnimplementedFeatureError const&) { } + catch (StackTooDeepError const&) + { + } } void FuzzerUtil::runCompiler(string const& _input, bool _quiet)