Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yul FunctionCallFinder uses FunctionName instead of strings as search key #15840

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

clonker
Copy link
Member

@clonker clonker commented Feb 10, 2025

description is in the title

@clonker clonker requested a review from nikola-matic February 10, 2025 08:42
@clonker clonker force-pushed the function_call_finder_on_handle branch 4 times, most recently from 1fd9fd4 to 761970b Compare February 10, 2025 09:22
Copy link
Member

@cameel cameel left a comment

Choose a reason for hiding this comment

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

Looks like this is a bugfix so we should check if the bug had any observable effects and, if so, cover them with regression tests.

Other than that just, some minor style tweaks and simplifications.

std::vector<FunctionCall*> memoryGuardCalls = findFunctionCalls(_ast, "memoryguard", m_dialect);
// We will perform less aggressive inlining, if no ``memoryguard`` call is found.
if (!memoryGuardCalls.empty())
m_hasMemoryGuard = true;
if (auto const memoryGuard = m_dialect.findBuiltin("memoryguard"))
Copy link
Member

Choose a reason for hiding this comment

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

Oh, so this is a bugfix rather than just a refactor?

If I understand this correctly, the old code would run over all function calls and misdetect any function called memoryguard() as the actual builtin. And this could fool the compiler into thinking the code is memory-safe and doing potentially unsafe optimizations (inlining, stack evader).

Note that, unlike all other Yul builtins, memoryguard is currently not a reserved identifier. We don't allow defining functions named like builtins so you still can't name a function like this in pure Yul, but in inline assembly it's not a builtin. Fortunately looks like we do some name mangling on functions defined in inline assembly (it will end up as usr$memoryguard()), but I don't know if we can assume this code never runs on unmangled assembly - please check.

We should also add some memory guard tests covering inline assembly with functions/variables named like that. I don't think we have any right now.

Since we have not released in a while, looks like we'll get away without a changelog entry even if it turns out it did have some user-observable effects. This bug is probably still only on develop. I think it must have been #15520/#15347 where this slipped through and we have not released that yet.

Copy link
Member Author

@clonker clonker Feb 18, 2025

Choose a reason for hiding this comment

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

Huh, a fix by accident then. I was not (actively) aware that memoryguard is not a reserved identifier. If it was broken, it was broken before the builtin AST changes as well if I am interpreting this correctly. There, it just checked if the yulstring name of any function call matches "memoryguard". I'll see whether it can run on unmangled asm.

Copy link
Member Author

@clonker clonker Feb 19, 2025

Choose a reason for hiding this comment

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

Don't think it's possible with inline assembly:

yul::YulName translateIdentifier(yul::YulName _name) override
{
// Strictly, the dialect used by inline assembly (m_dialect) could be different
// from the Yul dialect we are compiling to. So we are assuming here that the builtin
// functions are identical. This should not be a problem for now since everything
// is EVM anyway.
if (m_dialect.findBuiltin(_name.str()))
return _name;
else
return yul::YulName{"usr$" + _name.str()};
}

As soon as it is not recognized as builtin (which would be the case for memoryguard), it gets the prefix. The compact JSON output does not contain the mangling yet, it's only added intermittently.

Other than that, this exists: libsolidity/syntaxTests/inlineAssembly/clash_with_non_reserved_pure_yul_builtin.sol. We could of course add another test in which it is shown that this is indeed mangled.

Copy link
Member Author

Choose a reason for hiding this comment

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

I have added a cmdline test that prints ir output for a contract with memoryguard identifiers. Then we can see that it indeed gets the prefix in all cases.

@cameel cameel added this to the 0.8.29 milestone Feb 18, 2025
@clonker clonker force-pushed the function_call_finder_on_handle branch from 761970b to a14754f Compare February 19, 2025 07:45
@clonker clonker force-pushed the function_call_finder_on_handle branch from a14754f to 32637d4 Compare February 19, 2025 07:48
@clonker clonker requested a review from cameel February 19, 2025 12:20
@ekpyron ekpyron removed this from the 0.8.29 milestone Feb 19, 2025
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.

3 participants