Skip to content

Commit

Permalink
Fix Yul stack output using standard json in the presence of warnings.
Browse files Browse the repository at this point in the history
  • Loading branch information
ekpyron committed Sep 3, 2024
1 parent 9b33e00 commit c746a7d
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 14 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Compiler Features:
* SMTChecker: Replace CVC4 as a possible BMC backend with cvc5.
* Standard JSON Interface: Do not perform IR optimization when only unoptimized IR is requested.
* Standard JSON Interface: Add ``transientStorageLayout`` output.
* Standard JSON Interface: For Yul input, properly produce output artifacts in case of warnings.
* Yul: Drop the deprecated typed Yul dialect that was only accessible via ``--yul`` in the CLI.
* Yul: The presence of types in untyped Yul dialects is now a parser error.
* Yul Optimizer: Caching of optimized IR to speed up optimization of contracts with bytecode dependencies.
Expand Down
26 changes: 12 additions & 14 deletions libsolidity/interface/StandardCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1620,7 +1620,7 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
std::string const& sourceContents = _inputsAndSettings.sources.begin()->second;

// Inconsistent state - stop here to receive error reports from users
if (!stack.parseAndAnalyze(sourceName, sourceContents) && stack.errors().empty())
if (!stack.parseAndAnalyze(sourceName, sourceContents) && !stack.hasErrors())
{
output["errors"].emplace_back(formatError(
Error::Type::InternalCompilerError,
Expand All @@ -1630,22 +1630,20 @@ Json StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
return output;
}

if (!stack.errors().empty())
for (auto const& error: stack.errors())
{
for (auto const& error: stack.errors())
{
auto err = std::dynamic_pointer_cast<Error const>(error);
auto err = std::dynamic_pointer_cast<Error const>(error);

output["errors"].emplace_back(formatErrorWithException(
stack,
*error,
err->type(),
"general",
""
));
}
return output;
output["errors"].emplace_back(formatErrorWithException(
stack,
*error,
err->type(),
"general",
""
));
}
if (stack.hasErrors())
return output;

std::string contractName = stack.parserResult()->name;

Expand Down
1 change: 1 addition & 0 deletions libyul/YulStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class YulStack: public langutil::CharStreamProvider

/// @returns the errors generated during parsing, analysis (and potentially assembly).
langutil::ErrorList const& errors() const { return m_errors; }
bool hasErrors() const { return m_errorReporter.hasErrors(); }

/// Pretty-print the input after having parsed it.
std::string print(
Expand Down
20 changes: 20 additions & 0 deletions test/cmdlineTests/standard_yul_output_warning/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"language": "Yul",
"sources":
{
"C":
{
"content": "{ let x := tload(0) tstore(add(x, 1), 0) }"
}
},
"settings":
{
"outputSelection":
{
"*": {
"*": ["evm.bytecode", "evm.assembly", "irOptimized"],
"": [ "*" ]
}
}
}
}
61 changes: 61 additions & 0 deletions test/cmdlineTests/standard_yul_output_warning/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"contracts": {
"C": {
"object": {
"evm": {
"assembly": " /* \"C\":99:100 */
0x00
/* \"C\":95:96 */
0x01
/* \"C\":60:68 */
dup2
tload
/* \"C\":88:97 */
add
/* \"C\":81:101 */
tstore
/* \"C\":27:117 */
stop
",
"bytecode": {
"functionDebugData": {},
"generatedSources": [],
"linkReferences": {},
"object": "<BYTECODE REMOVED>",
"opcodes":"<OPCODES REMOVED>",
"sourceMap":"<SOURCEMAP REMOVED>"
}
},
"irOptimized": "object \"object\" {
code {
{
let x := tload(0)
tstore(add(x, 1), 0)
}
}
}
"
}
}
},
"errors": [
{
"component": "general",
"formattedMessage": "Warning: 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.
--> C:1:21:
|
1 | { let x := tload(0) tstore(add(x, 1), 0) }
| ^^^^^^

",
"message": "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.",
"severity": "warning",
"sourceLocation": {
"end": 26,
"file": "C",
"start": 20
},
"type": "Warning"
}
]
}

0 comments on commit c746a7d

Please sign in to comment.