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

Fix storage layout comparison for function types, disallow internal functions in storage #1032

Merged
merged 22 commits into from
Jun 12, 2024

Conversation

ericglau
Copy link
Member

@ericglau ericglau commented Jun 5, 2024

This fixes 2 things:

  1. Fixes An error due to function defined in struct in library #1031. In storage layout comparisons, type changes involving function pointers caused an error because of an incorrect assertion. The original and updated types could be unrelated during the comparison, but getVisibilityChange was asserting that both are functions. We should only call getVisibilityChange if both the original and updated types are indeed functions.

  2. Fixes Disallow internal function types in storage #555. Internal functions are code pointers which will no longer be valid after an upgrade, so they should not be allowed. Added this as a validation error, and allow it to be skipped with the unsafeAllow.internal-function-storage option (if skipping, users need to make sure they always reassign the internal functions in storage variables during each upgrade).

@ericglau ericglau marked this pull request as ready for review June 6, 2024 20:44
@ericglau ericglau requested a review from a team June 6, 2024 20:45
@ericglau ericglau marked this pull request as draft June 6, 2024 20:46
@ericglau ericglau marked this pull request as ready for review June 6, 2024 20:51
@ericglau ericglau changed the title Fix function pointer comparison in storage layouts Fix storage layout comparison for function types in structs, disallow internal functions in structs Jun 6, 2024
@ernestognw ernestognw requested a review from cairoeth June 7, 2024 19:53
Copy link

@cairoeth cairoeth left a comment

Choose a reason for hiding this comment

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

mostly looks good, but shouldn't it also check for internal functions as a storage variable? for example:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract StorageUpgrade_FunctionType_Visibility_V2_Bad {
    function () internal m;
}

function m will break after an upgrade as it gets moved around storage, no? similar to internal functions in structs

Copy link
Member

@ernestognw ernestognw left a comment

Choose a reason for hiding this comment

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

Very interesting finding!

I wonder if we should document how to reset the internal function pointers in the docs. It's true we now have a clear instruction within the CLI but we're not providing a concrete example other than the one shared in #1031.

What do you think?

@ernestognw
Copy link
Member

mostly looks good, but shouldn't it also check for internal functions as a storage variable? for example:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract StorageUpgrade_FunctionType_Visibility_V2_Bad {
    function () internal m;
}

function m will break after an upgrade as it gets moved around storage, no? similar to internal functions in structs

Functions do not live in storage, so m will not change. Instead, its pointer will change.
It's fine that it changes given that an upgrade changes the implementation (i.e. the runtime code and its internal function pointers).

The issue with storing internal function pointers in storage is that after upgrading to another implementation, the pointer in storage is a pointer to code that isn't used anymore. That's why it needs reinitialization.

@ericglau
Copy link
Member Author

ericglau commented Jun 7, 2024

Agree we should check storage variables that have function types even outside of structs, and will add a section in the docs.

@cairoeth
Copy link

cairoeth commented Jun 7, 2024

mostly looks good, but shouldn't it also check for internal functions as a storage variable? for example:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract StorageUpgrade_FunctionType_Visibility_V2_Bad {
    function () internal m;
}

function m will break after an upgrade as it gets moved around storage, no? similar to internal functions in structs

Functions do not live in storage, so m will not change. Instead, its pointer will change. It's fine that it changes given that an upgrade changes the implementation (i.e. the runtime code and its internal function pointers).

The issue with storing internal function pointers in storage is that after upgrading to another implementation, the pointer in storage is a pointer to code that isn't used anymore. That's why it needs reinitialization.

Yup, meant to refer to the pointer changing when upgrading to a different implementation.

@ericglau ericglau marked this pull request as draft June 7, 2024 22:11
@ericglau ericglau changed the title Fix storage layout comparison for function types in structs, disallow internal functions in structs Fix storage layout comparison for function types, disallow internal functions in storage Jun 7, 2024
@ericglau ericglau marked this pull request as ready for review June 10, 2024 19:12
@ericglau ericglau requested review from cairoeth and ernestognw June 10, 2024 19:12
@ericglau
Copy link
Member Author

ericglau commented Jun 10, 2024

  • Code now handles variables that reference struct definitions outside of contracts, as per comment
  • Added new section in documentation
  • Added links from errors and docs to the new section
  • (To do outside of this PR) Define URL shortened link to the new doc section

docs/modules/ROOT/pages/faq.adoc Outdated Show resolved Hide resolved
packages/core/src/validate/run.ts Outdated Show resolved Hide resolved
@ericglau ericglau requested a review from frangio June 12, 2024 14:10
Copy link
Contributor

@frangio frangio left a comment

Choose a reason for hiding this comment

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

LGTM! Minor suggestion.

packages/core/src/validate/run.ts Outdated Show resolved Hide resolved
@ericglau ericglau merged commit f1a5d63 into OpenZeppelin:master Jun 12, 2024
11 checks passed
@ericglau ericglau deleted the fnpointers branch June 12, 2024 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

An error due to function defined in struct in library Disallow internal function types in storage
5 participants