diff --git a/Changelog.md b/Changelog.md index 7b15ce945885..65c04b106791 100644 --- a/Changelog.md +++ b/Changelog.md @@ -16,6 +16,8 @@ Compiler Features: Bugfixes: + * Commandline Interface: Report StackTooDeep errors in compiler mode as proper errors instead of printing diagnostic information meant for internal compiler errors. + * Error Reporting: Fix error locations not being shown for source files with empty names. * General: Fix internal compiler error when requesting IR AST outputs for interfaces and abstract contracts. * Metadata: Fix custom cleanup sequence missing from metadata when other optimizer settings have default values. * SMTChecker: Fix internal compiler error when analyzing overflowing expressions or bitwise negation of unsigned types involving constants. diff --git a/liblangutil/SourceReferenceFormatter.cpp b/liblangutil/SourceReferenceFormatter.cpp index c48cb328d5f9..12308bf0d40b 100644 --- a/liblangutil/SourceReferenceFormatter.cpp +++ b/liblangutil/SourceReferenceFormatter.cpp @@ -114,11 +114,11 @@ AnsiColorized SourceReferenceFormatter::diagColored() const void SourceReferenceFormatter::printSourceLocation(SourceReference const& _ref) { - if (_ref.sourceName.empty()) - return; // Nothing we can print here - if (_ref.position.line < 0) { + if (_ref.sourceName.empty()) + return; // Nothing we can print here + frameColored() << "-->"; m_stream << ' ' << _ref.sourceName << '\n'; return; // No line available, nothing else to print diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 2748c09cda94..9582939f5e25 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -827,7 +827,12 @@ YulStack CompilerStack::loadGeneratedIR(std::string const& _ir) const yulAnalysisSuccessful, _ir + "\n\n" "Invalid IR generated:\n" + - SourceReferenceFormatter::formatErrorInformation(stack.errors(), stack) + "\n" + SourceReferenceFormatter::formatErrorInformation( + stack.errors(), + stack, // _charStreamProvider + false, // _colored + true // _withErrorIds + ) + "\n" ); return stack; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 71fbf17e288b..6bd5cd2317b3 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -131,7 +131,7 @@ Json formatErrorWithException( ); if (std::string const* description = _exception.comment()) - message = ((_message.length() > 0) ? (_message + ":") : "") + *description; + message = ((_message.length() > 0) ? (_message + ": ") : "") + *description; else message = _message; @@ -1412,6 +1412,7 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu )); } } + // NOTE: This includes langutil::StackTooDeepError. catch (CompilerError const& _exception) { errors.emplace_back(formatErrorWithException( @@ -1422,14 +1423,22 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu "Compiler error (" + _exception.lineInfo() + ")" )); } - catch (InternalCompilerError const& _exception) + catch (yul::StackTooDeepError const& _exception) { errors.emplace_back(formatErrorWithException( compilerStack, _exception, + Error::Type::YulException, + "general", + "" // No prefix needed. These messages already say it's a "stack too deep" error. + )); + } + catch (InternalCompilerError const&) + { + errors.emplace_back(formatError( Error::Type::InternalCompilerError, "general", - "Internal compiler error (" + _exception.lineInfo() + ")" + "Internal compiler error:\n" + boost::current_exception_diagnostic_information() )); } catch (UnimplementedFeatureError const& _exception) @@ -1437,24 +1446,20 @@ Json StandardCompiler::compileSolidity(StandardCompiler::InputsAndSettings _inpu // let StandardCompiler::compile handle this throw _exception; } - catch (yul::YulException const& _exception) + catch (YulAssertion const&) { - errors.emplace_back(formatErrorWithException( - compilerStack, - _exception, + errors.emplace_back(formatError( Error::Type::YulException, "general", - "Yul exception" + "Yul assertion failed:\n" + boost::current_exception_diagnostic_information() )); } - catch (smtutil::SMTLogicError const& _exception) + catch (smtutil::SMTLogicError const&) { - errors.emplace_back(formatErrorWithException( - compilerStack, - _exception, + errors.emplace_back(formatError( Error::Type::SMTLogicException, "general", - "SMT logic exception" + "SMT logic error:\n" + boost::current_exception_diagnostic_information() )); } catch (...) @@ -1827,7 +1832,10 @@ Json StandardCompiler::compile(Json const& _input) noexcept } catch (...) { - return formatFatalError(Error::Type::InternalCompilerError, "Internal exception in StandardCompiler::compile: " + boost::current_exception_diagnostic_information()); + return formatFatalError( + Error::Type::InternalCompilerError, + "Uncaught exception:\n" + boost::current_exception_diagnostic_information() + ); } } diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index aa3e23e2626f..b6ff862b3850 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -113,7 +113,36 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect( {}, std::move(_objectStructure) ).analyze(_astRoot); - yulAssert(success && !errors.hasErrors(), "Invalid assembly/yul code."); + + if (!success) + { + auto formatErrors = [](ErrorList const& _errorList) { + std::vector formattedErrors; + for (std::shared_ptr const& error: _errorList) + { + yulAssert(error->comment()); + formattedErrors.push_back(fmt::format( + // Intentionally not showing source locations because we don't have the original + // source here and it's unlikely they match the pretty-printed version. + // They may not even match the original source if the AST was modified by the optimizer. + "- {} {}: {}", + Error::formatErrorType(error->type()), + error->errorId().error, + *error->comment() + )); + } + return joinHumanReadable(formattedErrors, "\n"); + }; + + yulAssert(errors.hasErrors(), "Yul analysis failed but did not report any errors."); + yulAssert(false, fmt::format( + "{}\n\nExpected valid Yul, but errors were reported during analysis:\n{}", + AsmPrinter{_dialect}(_astRoot), + formatErrors(errorList) + )); + } + + yulAssert(!errors.hasErrors()); return analysisInfo; } diff --git a/libyul/Exceptions.h b/libyul/Exceptions.h index f92268180971..4f08e192f788 100644 --- a/libyul/Exceptions.h +++ b/libyul/Exceptions.h @@ -36,7 +36,7 @@ namespace solidity::yul struct YulException: virtual util::Exception {}; struct OptimizerException: virtual YulException {}; struct CodegenException: virtual YulException {}; -struct YulAssertion: virtual YulException {}; +struct YulAssertion: virtual util::Exception {}; struct StackTooDeepError: virtual YulException { diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 4fd730096e85..e57cd77a98a2 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -1009,6 +1009,7 @@ void CommandLineInterface::compile() if (!successful) solThrow(CommandLineExecutionError, ""); } + // NOTE: This includes langutil::StackTooDeepError. catch (CompilerError const& _exception) { m_hasOutput = true; @@ -1018,6 +1019,15 @@ void CommandLineInterface::compile() ); solThrow(CommandLineExecutionError, ""); } + catch (yul::StackTooDeepError const& _exception) + { + m_hasOutput = true; + formatter.printExceptionInformation( + _exception, + Error::errorSeverity(Error::Type::YulException) + ); + solThrow(CommandLineExecutionError, ""); + } } void CommandLineInterface::handleCombinedJSON() diff --git a/solc/main.cpp b/solc/main.cpp index c6c3df7a2eba..49994559423a 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -51,6 +51,12 @@ int main(int argc, char** argv) std::cerr << boost::diagnostic_information(_exception); return 2; } + catch (yul::YulAssertion const& _exception) + { + std::cerr << "Yul assertion failed:" << std::endl; + std::cerr << boost::diagnostic_information(_exception); + return 2; + } catch (...) { std::cerr << "Uncaught exception:" << std::endl; diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index 3cb908118ea2..ccf4added41e 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -197,15 +197,15 @@ void CommonSyntaxTest::printErrorList( for (auto const& error: _errorList) { { - util::AnsiColorized scope( + util::AnsiColorized formattedStream( _stream, _formatted, {BOLD, SourceReferenceFormatter::errorTextColor(Error::errorSeverity(error.type))} ); - _stream << _linePrefix << Error::formatErrorType(error.type); + formattedStream << _linePrefix << Error::formatErrorType(error.type); if (error.errorId.has_value()) - _stream << ' ' << error.errorId->error; - _stream << ": "; + formattedStream << ' ' << error.errorId->error; + formattedStream << ": "; } if (!error.sourceName.empty() || error.locationStart >= 0 || error.locationEnd >= 0) { diff --git a/test/cmdlineTests/stack_too_deep_from_code_transform/args b/test/cmdlineTests/stack_too_deep_from_code_transform/args new file mode 100644 index 000000000000..b182392aac61 --- /dev/null +++ b/test/cmdlineTests/stack_too_deep_from_code_transform/args @@ -0,0 +1 @@ +--via-ir --bin diff --git a/test/cmdlineTests/stack_too_deep_from_code_transform/err b/test/cmdlineTests/stack_too_deep_from_code_transform/err new file mode 100644 index 000000000000..588f4d437945 --- /dev/null +++ b/test/cmdlineTests/stack_too_deep_from_code_transform/err @@ -0,0 +1,6 @@ +Error: Cannot swap Variable value23 with Slot 0x20: too deep in the stack by 9 slots in [ RET value23 value22 value21 value20 value19 value18 value17 value16 value15 value14 value13 value12 value11 value10 value9 value8 value7 value6 value5 value4 value3 value2 value1 value0 pos 0x20 ] +memoryguard was present. + --> stack_too_deep_from_code_transform/input.sol:1:1: + | +1 | contract C { + | ^ (Relevant source part starts here and spans across multiple lines). diff --git a/test/cmdlineTests/stack_too_deep_from_code_transform/exit b/test/cmdlineTests/stack_too_deep_from_code_transform/exit new file mode 100644 index 000000000000..d00491fd7e5b --- /dev/null +++ b/test/cmdlineTests/stack_too_deep_from_code_transform/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/stack_too_deep_from_code_transform/input.sol b/test/cmdlineTests/stack_too_deep_from_code_transform/input.sol new file mode 100644 index 000000000000..aae75b841ce0 --- /dev/null +++ b/test/cmdlineTests/stack_too_deep_from_code_transform/input.sol @@ -0,0 +1,10 @@ +contract C { + function f() public { + uint b; + abi.encodePacked( + b, b, b, b, b, b, b, b, + b, b, b, b, b, b, b, b, + b, b, b, b, b, b, b, b + ); + } +} diff --git a/test/cmdlineTests/standard_empty_file_name/output.json b/test/cmdlineTests/standard_empty_file_name/output.json index 1fd016e54e81..b4e525c21516 100644 --- a/test/cmdlineTests/standard_empty_file_name/output.json +++ b/test/cmdlineTests/standard_empty_file_name/output.json @@ -4,6 +4,10 @@ "component": "general", "errorCode": "2904", "formattedMessage": "DeclarationError: Declaration \"A\" not found in \"\" (referenced as \".\"). + --> :2:24: + | +2 | pragma solidity >=0.0; import {A} from \".\"; + | ^^^^^^^^^^^^^^^^^^^^ ", "message": "Declaration \"A\" not found in \"\" (referenced as \".\").", diff --git a/test/cmdlineTests/standard_stack_too_deep_from_code_transform/in.sol b/test/cmdlineTests/standard_stack_too_deep_from_code_transform/in.sol new file mode 100644 index 000000000000..aae75b841ce0 --- /dev/null +++ b/test/cmdlineTests/standard_stack_too_deep_from_code_transform/in.sol @@ -0,0 +1,10 @@ +contract C { + function f() public { + uint b; + abi.encodePacked( + b, b, b, b, b, b, b, b, + b, b, b, b, b, b, b, b, + b, b, b, b, b, b, b, b + ); + } +} diff --git a/test/cmdlineTests/standard_stack_too_deep_from_code_transform/input.json b/test/cmdlineTests/standard_stack_too_deep_from_code_transform/input.json new file mode 100644 index 000000000000..a01e842b384d --- /dev/null +++ b/test/cmdlineTests/standard_stack_too_deep_from_code_transform/input.json @@ -0,0 +1,12 @@ +{ + "language": "Solidity", + "sources": { + "in.sol": {"urls": ["standard_stack_too_deep_from_code_transform/in.sol"]} + }, + "settings": { + "viaIR": true, + "outputSelection": { + "*": {"*": ["evm.bytecode"]} + } + } +} diff --git a/test/cmdlineTests/standard_stack_too_deep_from_code_transform/output.json b/test/cmdlineTests/standard_stack_too_deep_from_code_transform/output.json new file mode 100644 index 000000000000..b4b0139fee69 --- /dev/null +++ b/test/cmdlineTests/standard_stack_too_deep_from_code_transform/output.json @@ -0,0 +1,29 @@ +{ + "errors": [ + { + "component": "general", + "formattedMessage": "YulException: Cannot swap Variable value23 with Slot 0x20: too deep in the stack by 9 slots in [ RET value23 value22 value21 value20 value19 value18 value17 value16 value15 value14 value13 value12 value11 value10 value9 value8 value7 value6 value5 value4 value3 value2 value1 value0 pos 0x20 ] +memoryguard was present. + --> in.sol:1:1: + | +1 | contract C { + | ^ (Relevant source part starts here and spans across multiple lines). + +", + "message": "Cannot swap Variable value23 with Slot 0x20: too deep in the stack by 9 slots in [ RET value23 value22 value21 value20 value19 value18 value17 value16 value15 value14 value13 value12 value11 value10 value9 value8 value7 value6 value5 value4 value3 value2 value1 value0 pos 0x20 ] +memoryguard was present.", + "severity": "error", + "sourceLocation": { + "end": 206, + "file": "in.sol", + "start": 0 + }, + "type": "YulException" + } + ], + "sources": { + "in.sol": { + "id": 0 + } + } +}