Skip to content

The optimizer incorrectly removes assembly block that initializes function pointer #15716

@0xkarmacoma

Description

@0xkarmacoma

Description

When using an assembly block to initialize a function pointer with a value provided externally, starting from 0.8.13 the optimizer removes the sstore that initializes it.

Note: this is related to #15707, but the PoC was wrong so I think this deserves a separate issue/discussion. This new PoC shows that the initializer does not always revert.

Steps to reproduce

There was an error in the PoC, the intent was not for the uninitialized call to always revert, but for the constructor argument x to dynamically initialize foo. I know it's weird, but I got this to work on 0.8.12:

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.12;

contract A {
    // events
    event Success();

    // storage
    function() internal foo;

    constructor(uint256 x) {
        assembly {
            sstore(foo.slot, x)
        }

        foo();
    }

    // public so that it's not eliminated by the optimizer
    function bar() public {
        emit Success();
    }
}

Manually inspecting the deployment bytecode shows that bar() is at 0x14b, so if we call it like this in a test:

import {A} from "src/A.sol";

contract ATest {
    function test_dyn_fun_ptr() public {
        new A(0x14b << 0x20);
    }
}

then it actually does set and call bar() as expected on 0.8.12:

Ran 1 test for test/A.t.sol:ATest
[PASS] test_dyn_fun_ptr() (gas: 97719)
Traces:
  [97719] ATest::test_dyn_fun_ptr()
    ├─ [65075] → new A@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    │   ├─ emit Success()
    │   └─ ← [Return] 208 bytes of code
    └─ ← [Stop] 

but the sstore is eliminated from 0.8.13 and up as reported previously

Environment

  • Compiler version: 0.8.28
  • Target EVM version (as per compiler settings): Cancun
  • Framework/IDE (e.g. Truffle or Remix): foundry
  • EVM execution environment / backend / blockchain client: n/a
  • Operating system: Linux/macOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions