Skip to content

Fix named error parameter encoding order in IR codegen - #16453

Open
nikola-matic wants to merge 4 commits into
developfrom
fix-named-error-paramater-encoding-in-ir
Open

Fix named error parameter encoding order in IR codegen#16453
nikola-matic wants to merge 4 commits into
developfrom
fix-named-error-paramater-encoding-in-ir

Conversation

@nikola-matic

@nikola-matic nikola-matic commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Closes #16452

Comment thread libsolidity/codegen/ir/IRGeneratorForStatements.cpp Outdated
@cameel cameel changed the title Fix named error paremeter encoding order in IR codegen Fix named error parameter encoding order in IR codegen Feb 9, 2026
@github-actions github-actions Bot added the stale The issue/PR was marked as stale because it has been open for too long. label Feb 24, 2026
@nikola-matic nikola-matic removed the stale The issue/PR was marked as stale because it has been open for too long. label Feb 24, 2026
@github-actions github-actions Bot added the stale The issue/PR was marked as stale because it has been open for too long. label Mar 11, 2026
@argotorg argotorg deleted a comment from github-actions Bot Mar 11, 2026
@argotorg argotorg deleted a comment from github-actions Bot Mar 11, 2026
@nikola-matic nikola-matic removed the stale The issue/PR was marked as stale because it has been open for too long. label Mar 11, 2026
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch 3 times, most recently from 01fe6b9 to 0f978ea Compare March 13, 2026 15:34

@cameel cameel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a lot more tests and a bug list entry.

Comment thread test/libsolidity/semanticTests/errors/require_error_named_parameters.sol Outdated
Comment thread Changelog.md
@cameel cameel added the codegen error Compiler generates invalid code. Critical. label Mar 16, 2026
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch 5 times, most recently from a6503ed to 8bd6e00 Compare March 17, 2026 13:15
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch from 8bd6e00 to 071ea8a Compare March 18, 2026 08:04
@nikola-matic
nikola-matic requested a review from cameel March 18, 2026 08:05
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch from 071ea8a to 4524716 Compare March 18, 2026 12:00
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch 2 times, most recently from 6c95a91 to 04f0ce0 Compare March 25, 2026 12:47
Comment thread Changelog.md Outdated
Comment thread docs/bugs.json Outdated
@@ -1,4 +1,17 @@
[
{
"uid": "SOL-2026-2",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a heads-up to bump this in case we merge #16508 first.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And another heads-up for the date in blog post link.

Comment thread docs/bugs.json Outdated
auto const& errorConstructorCall = dynamic_cast<FunctionCall const&>(*arguments[1]);
appendCode() << m_utils.requireWithErrorFunction(errorConstructorCall) << "(" <<IRVariable(*arguments[0]).name();
for (auto argument: errorConstructorCall.arguments())
for (auto argument: errorConstructorCall.sortedArguments())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that there are still some things we can do to make these errors less likely without going for full #16529. One of them is to always use sortedArguments() by default.

We have very few places where we need arguments in call order. I looked through the code and in almost all cases where arguments() is invoked, sortedArguments() would both would work, either because the function has fewer than two arguments or because it's a case where we don't allow named arguments. We should change all of them to sortedArguments(). This may prevent more bugs creeping in when we extend named parameter support to more places. People will also be less likely to choose arguments() just because the surrounding code uses it.

I would also rename them to argumentsInDefinitionOrder() and argumentsInCallOrder(). The current naming makes it seem like the arguments() is the default one and sortedArguments() is something special. The docstring should also have a big fat warning explaining the difference.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This, along with the extra tests for named parameters could be extracted into a separate PR and merged quicker.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC you said on the chat you had some problem with sortedArguments() so you left some of them as is. What was that specifically?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC you said on the chat you had some problem with sortedArguments() so you left some of them as is. What was that specifically?

The issues with them mostly lie on the frontend side whilst AST & annotations are still being populated/changed, which then causes some asserts to be triggered. All of the backend ones have been replaced though and are fine.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, regarding the naming - I would strongly prefer doing that in a follow up PR as it's going to touch significantly more occurrences than were changed here.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, doing the renaming in a follow-up is fine.

revert NamedArgsError3({c: 9, a: 2, b: 7});
}
function trigger4() external pure {
revert NamedArgsError4({b: "error", a: 2, c: 9, d: true});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, I thought mismatched types would produce an error without the fix, but I just checked this example on 0.8.34 and it still compiles. Makes sense given that the error is in the codegen, not in analysis, but this makes the bug worse than we assumed based on the information we had when we discussed it. Why didn't you say anything about it?

When we discussed this, the assumption was that in most cases bad code would not even compile due to type mismatch and you could at most swap two numbers or something. If any combination compiles, it's much easier to run into the bug.

The consequences are also a bit different. Now you can have errors whose encoded parameters do not match the selector. Depending on how the decoder works, it may result in a decoding failure, which is at least better than accepting broken data (but still worse than a compilation error).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you started working on the blog post? We actually still need to prepare and send the proper impact analysis first. You can explore the consequences of the above in it.

Comment thread docs/bugs.json Outdated
@github-actions github-actions Bot added the stale The issue/PR was marked as stale because it has been open for too long. label Apr 16, 2026
@nikola-matic nikola-matic removed the stale The issue/PR was marked as stale because it has been open for too long. label Apr 16, 2026
@cameel cameel added this to the 0.8.35 milestone Apr 18, 2026
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch from 04f0ce0 to 3529a21 Compare April 21, 2026 10:36
@argotorg argotorg deleted a comment from github-actions Bot Apr 27, 2026

@cameel cameel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix itself and test coverage seem mostly fine now (just some minor tweaks left), but there are still unresolved comments regarding the bug list entry. We also have to take a second look at the impact analysis in the light of #16453 (comment).

Comment thread libsolidity/codegen/ir/IRGeneratorForStatements.cpp
@nikola-matic nikola-matic modified the milestones: 0.8.35, 0.8.36 May 12, 2026
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch 2 times, most recently from e51ddcb to 5ed545f Compare May 14, 2026 13:12
@nikola-matic
nikola-matic requested a review from cameel May 14, 2026 13:12
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch 2 times, most recently from 91d80d7 to b6b4ffe Compare June 17, 2026 11:11
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch from b6b4ffe to 3a88bc1 Compare July 21, 2026 08:19
cameel
cameel previously approved these changes Aug 6, 2026
Comment on lines +47 to +48
// bytesAndBool() -> FAILURE, hex"ea504c15", 0x40, 1, 4, left(0xdeadbeef)
// mixedDynamic() -> FAILURE, hex"e45ff7f0", 0x80, 7, 0xc0, 1, 4, "test", 2, left(0xcafe)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// bytesAndBool() -> FAILURE, hex"ea504c15", 0x40, 1, 4, left(0xdeadbeef)
// mixedDynamic() -> FAILURE, hex"e45ff7f0", 0x80, 7, 0xc0, 1, 4, "test", 2, left(0xcafe)
// bytesAndBool() -> FAILURE, hex"ea504c15", 0x40, true, 4, left(0xdeadbeef)
// mixedDynamic() -> FAILURE, hex"e45ff7f0", 0x80, 7, 0xc0, true, 4, "test", 2, left(0xcafe)

Same in require_error_named_parameters_literal_conversions.sol.

Comment thread docs/bugs.json Outdated
"uid": "SOL-2026-4",
"name": "MisorderedNamedParametersInRequireWithCustomErrors",
"summary": "Custom error arguments passed to `require` using named-parameter syntax are ABI-encoded in call-site order instead of declaration order when compiling via IR.",
"description": "When a custom error is passed as the second argument of `require` and instantiated using named-parameter syntax (e.g., `require(cond, MyError({b: 1, a: 2}))`), the IR-based code generator encodes the arguments in the order they appear at the call site rather than reordering them to match the parameter order declared in the error definition. The arguments are still type-checked against their named slots, but the type system does not require the call-site order to match the declaration, so the bug can be triggered even when the supplied values would type-check in either order. When all arguments occupy the same number of stack slots (e.g., all value types), the resulting payload contains the values in the wrong positions for the error's signature. When the call-site argument types differ in stack-slot width (for example a `calldata` reference next to a value type), the misordering also misaligns the helper's parameters slot-by-slot, producing a payload of an entirely different shape than the error's ABI signature — values land in unrelated positions, dynamic-type lengths are read from arbitrary stack values, and string/bytes data may be copied from arbitrary calldata offsets, in the worst case triggering an EVM-level error during encoding. The bug is specific to custom errors passed as the second argument of `require`. Standalone `revert ErrorName({...})` statements, event emissions, function calls, struct constructor invocations and other constructs supporting named parameters are not affected. The evmasm pipeline is also unaffected.",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use double backticks in these.

Comment thread docs/bugs.json Outdated
"uid": "SOL-2026-4",
"name": "MisorderedNamedParametersInRequireWithCustomErrors",
"summary": "Custom error arguments passed to `require` using named-parameter syntax are ABI-encoded in call-site order instead of declaration order when compiling via IR.",
"description": "When a custom error is passed as the second argument of `require` and instantiated using named-parameter syntax (e.g., `require(cond, MyError({b: 1, a: 2}))`), the IR-based code generator encodes the arguments in the order they appear at the call site rather than reordering them to match the parameter order declared in the error definition. The arguments are still type-checked against their named slots, but the type system does not require the call-site order to match the declaration, so the bug can be triggered even when the supplied values would type-check in either order. When all arguments occupy the same number of stack slots (e.g., all value types), the resulting payload contains the values in the wrong positions for the error's signature. When the call-site argument types differ in stack-slot width (for example a `calldata` reference next to a value type), the misordering also misaligns the helper's parameters slot-by-slot, producing a payload of an entirely different shape than the error's ABI signature — values land in unrelated positions, dynamic-type lengths are read from arbitrary stack values, and string/bytes data may be copied from arbitrary calldata offsets, in the worst case triggering an EVM-level error during encoding. The bug is specific to custom errors passed as the second argument of `require`. Standalone `revert ErrorName({...})` statements, event emissions, function calls, struct constructor invocations and other constructs supporting named parameters are not affected. The evmasm pipeline is also unaffected.",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When all arguments occupy the same number of stack slots (e.g., all value types)

There are value types that occupy two stack slots (external function pointers).

in the worst case triggering an EVM-level error during encoding.

That's actually the best case :) The worst one is successfully encoding the wrong thing.

@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch from 3a88bc1 to dc9457b Compare August 6, 2026 11:20
@nikola-matic
nikola-matic force-pushed the fix-named-error-paramater-encoding-in-ir branch from dc9457b to dbc7be8 Compare August 6, 2026 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codegen error Compiler generates invalid code. Critical.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom error named parameters passed in call order instead of declaration order

2 participants