Skip to content

Fix O(n²) in VarNameCleaner::findCleanName using per-base-name counter#16563

Open
msooseth wants to merge 8 commits intodevelopfrom
fix-on2-namecleaner
Open

Fix O(n²) in VarNameCleaner::findCleanName using per-base-name counter#16563
msooseth wants to merge 8 commits intodevelopfrom
fix-on2-namecleaner

Conversation

@msooseth
Copy link
Copy Markdown
Contributor

When many variables share the same stripped base name, findCleanName would probe name_1, name_2, ..., name_N sequentially for each variable, resulting in O(n²) calls to isUsedName (which involves regex matching via isRestrictedIdentifier). This was the dominant cost in fuzzer timeouts where the optimizer generated many variables.

Track a counter per base name (m_nextSuffix) so we resume from the last assigned suffix instead of reprobing from 1 each time.

Found by the fuzzer with custom optimization ordering.

@msooseth
Copy link
Copy Markdown
Contributor Author

if you are very happy about this, then let's push this through instead that will fix all of this:

#15969

Copy link
Copy Markdown
Contributor

@nikola-matic nikola-matic left a comment

Choose a reason for hiding this comment

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

@clonker fixed the failing arch build - please rebase to fix the build.

@msooseth msooseth force-pushed the fix-on2-namecleaner branch from 108f6b6 to 402076b Compare April 1, 2026 09:14
nikola-matic
nikola-matic previously approved these changes Apr 9, 2026
Copy link
Copy Markdown
Contributor

@nikola-matic nikola-matic left a comment

Choose a reason for hiding this comment

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

Can you squash some of the commits please. Also, perfectly fine with this as a stop-gap until Yul IDs are merged (@clonker you wanna give this PR a final look before we merge?)

YulName newNameSuffixed = YulName{newName.str() + "_" + std::to_string(nextSuffix)};
if (!isUsedName(newNameSuffixed))
{
++nextSuffix;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if i interpret everything correctly, this is supposed to increment the suffix in the map, right? but I don't think it does, it's retrieved by value so the map value isnt updated, ever.

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.

Yes. I'm sorry. It was written correctly and then broken. in 4b13837

Fixing now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Haha some idiot probably suggested removing the reference. Wait a minute...

msooseth and others added 7 commits April 9, 2026 17:04
When many variables share the same stripped base name, findCleanName
would probe name_1, name_2, ..., name_N sequentially for each
variable, resulting in O(n²) calls to isUsedName (which involves
regex matching via isRestrictedIdentifier). This was the dominant
cost in fuzzer timeouts where the optimizer generated many variables.

Track a counter per base name (m_nextSuffix) so we resume from the
last assigned suffix instead of reprobing from 1 each time.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Fix more

Update

More tests

More tests
Co-authored-by: Nikola Matić <nikola.matic@ethereum.org>
Copy link
Copy Markdown
Member

@clonker clonker left a comment

Choose a reason for hiding this comment

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

Happy to approve if you put the const back :) also let's think about extracting this (plus the NameSimplifier) into an external tool that can be run on demand.

}

YulName VarNameCleaner::findCleanName(YulName const& _name) const
YulName VarNameCleaner::findCleanName(YulName const& _name)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
YulName VarNameCleaner::findCleanName(YulName const& _name)
YulName VarNameCleaner::findCleanName(YulName const& _name) const

since the cache is now mutable, you can put back the const :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants