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

bug: cfg graph starts from offset 0x01 instead of 0x00 #499

Open
2 tasks done
alessandromazza98 opened this issue Sep 18, 2024 · 1 comment
Open
2 tasks done

bug: cfg graph starts from offset 0x01 instead of 0x00 #499

alessandromazza98 opened this issue Sep 18, 2024 · 1 comment
Assignees
Labels
T-bug Type: bug

Comments

@alessandromazza98
Copy link

Component

Heimdall (Core)

Have you ensured that you are up to date?

  • Bifrost
  • Heimdall

What version of Heimdall are you on?

heimdall 0.8.4

Operating System

macOS (Apple Silicon)

Describe the bug

I'm generating the cfg of a very simple contract to try heimdall.

everything works fine but I don't understand why heimdall uses offset in the bytecode starting from 0x01 instead of 0x00.

This creates some confusion because, take the example I have in the image, the first block has a jumpi that should point to 0x20. But heimdall shows the jumpdest at offset 0x21 (because of the shifts of the offset). While at offset 0x20 heimdall shows a different opcode (JUMP in this example).

The contract:

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.27;
contract Faucet {
  // Give out ether to anyone who asks
  function withdraw(uint256 _withdrawAmount, address payable _to) public {
    // Limit withdrawal amount
    require(_withdrawAmount <= 1000000000000);
    // Send the amount to the address that requested it
    _to.transfer(_withdrawAmount);
  }
  fallback() external payable {}
}

I took the runtime bytecode through solc and gave it to heimdall cfg

The graph:
image

tg discussion here: https://t.me/heimdallsupport/388

@chen4903
Copy link

chen4903 commented Feb 11, 2025

I have the same problem with a simple demo:

use heimdall_cfg::{cfg, CfgArgsBuilder};

pub async fn build_cfg() -> Result<(), Box<dyn std::error::Error>> {
    let args = CfgArgsBuilder::new()
        // .target("0x9f00c43700bc0000Ff91bE00841F8e04c0495000".to_string())
        // .rpc_url("https://eth.llamarpc.com".to_string())
        .target("0x6080604052348015600e575f80fd5b50600436106030575f3560e01c80632125b65b146034578063b69ef8a8146044575b5f80fd5b6044603f3660046046565b505050565b005b5f805f606084860312156057575f80fd5b833563ffffffff811681146069575f80fd5b925060208401356001600160a01b03811681146083575f80fd5b915060408401356001600160e01b0381168114609d575f80fd5b80915050925092509256".to_string())
        .build()?;

    let result = cfg(args).await?;

    println!("Contract Cfg: {:#?}", result);

    Ok(())
}

This is the result of it:

Contract Cfg: CfgResult {
    graph: Graph {
        Ty: "Directed",
        node_count: 17,
        edge_count: 16,
        edges: (0, 1), (0, 2), (2, 3), (3, 4), (4, 5), (5, 6), (5, 7), (7, 8), (7, 9), (9, 10), (9, 11), (4, 12), (3, 13), (13, 14), (13, 15), (2, 16),
        node weights: {
            0: "0x01 PUSH1 0x80\n0x03 PUSH1 0x40\n0x05 MSTORE \n0x06 CALLVALUE \n0x07 DUP1 \n0x08 ISZERO \n0x09 PUSH1 0x0e\n0x0b JUMPI \n",
            1: "0x0c PUSH0 0\n0x0d DUP1 \n0x0e REVERT \n",
            2: "0x0f JUMPDEST \n0x10 POP \n0x11 PUSH1 0x04\n0x13 CALLDATASIZE \n0x14 LT \n0x15 PUSH1 0x30\n0x17 JUMPI \n",
            3: "0x18 PUSH0 0\n0x19 CALLDATALOAD \n0x1a PUSH1 0xe0\n0x1c SHR \n0x1d DUP1 \n0x1e PUSH4 0x2125b65b\n0x23 EQ \n0x24 PUSH1 0x34\n0x26 JUMPI \n",
            4: "0x35 JUMPDEST \n0x36 PUSH1 0x44\n0x38 PUSH1 0x3f\n0x3a CALLDATASIZE \n0x3b PUSH1 0x04\n0x3d PUSH1 0x46\n0x3f JUMP \n0x47 JUMPDEST \n0x48 PUSH0 0\n0x49 DUP1 \n0x4a PUSH0 0\n0x4b PUSH1 0x60\n0x4d DUP5 \n0x4e DUP7 \n0x4f SUB \n0x50 SLT \n0x51 ISZERO \n0x52 PUSH1 0x57\n0x54 JUMPI \n",
            5: "0x58 JUMPDEST \n0x59 DUP4 \n0x5a CALLDATALOAD \n0x5b PUSH4 0xffffffff\n0x60 DUP2 \n0x61 AND \n0x62 DUP2 \n0x63 EQ \n0x64 PUSH1 0x69\n0x66 JUMPI \n",
            6: "0x67 PUSH0 0\n0x68 DUP1 \n0x69 REVERT \n",
            7: "0x6a JUMPDEST \n0x6b SWAP3 \n0x6c POP \n0x6d PUSH1 0x20\n0x6f DUP5 \n0x70 ADD \n0x71 CALLDATALOAD \n0x72 PUSH1 0x01\n0x74 PUSH1 0x01\n0x76 PUSH1 0xa0\n0x78 SHL \n0x79 SUB \n0x7a DUP2 \n0x7b AND \n0x7c DUP2 \n0x7d EQ \n0x7e PUSH1 0x83\n0x80 JUMPI \n",
            8: "0x81 PUSH0 0\n0x82 DUP1 \n0x83 REVERT \n",
            9: "0x84 JUMPDEST \n0x85 SWAP2 \n0x86 POP \n0x87 PUSH1 0x40\n0x89 DUP5 \n0x8a ADD \n0x8b CALLDATALOAD \n0x8c PUSH1 0x01\n0x8e PUSH1 0x01\n0x90 PUSH1 0xe0\n0x92 SHL \n0x93 SUB \n0x94 DUP2 \n0x95 AND \n0x96 DUP2 \n0x97 EQ \n0x98 PUSH1 0x9d\n0x9a JUMPI \n",
            10: "0x9b PUSH0 0\n0x9c DUP1 \n0x9d REVERT \n",
            11: "0x9e JUMPDEST \n0x9f DUP1 \n0xa0 SWAP2 \n0xa1 POP \n0xa2 POP \n0xa3 SWAP3 \n0xa4 POP \n0xa5 SWAP3 \n0xa6 POP \n0xa7 SWAP3 \n0xa8 JUMP \n0x40 JUMPDEST \n0x41 POP \n0x42 POP \n0x43 POP \n0x44 JUMP \n0x45 JUMPDEST \n0x46 STOP \n",
            12: "0x55 PUSH0 0\n0x56 DUP1 \n0x57 REVERT \n",
            13: "0x27 DUP1 \n0x28 PUSH4 0xb69ef8a8\n0x2d EQ \n0x2e PUSH1 0x44\n0x30 JUMPI \n",
            14: "0x45 JUMPDEST \n0x46 STOP \n",
            15: "0x31 JUMPDEST \n0x32 PUSH0 0\n0x33 DUP1 \n0x34 REVERT \n",
            16: "0x31 JUMPDEST \n0x32 PUSH0 0\n0x33 DUP1 \n0x34 REVERT \n",
        },
        edge weights: {
            0: "false",
            1: "true",
            2: "false",
            3: "true",
            4: "true",
            5: "false",
            6: "true",
            7: "false",
            8: "true",
            9: "false",
            10: "true",
            11: "false",
            12: "false",
            13: "true",
            14: "true",
            15: "true",
        },
    },
}

Regarding to the 2: "0x0f JUMPDEST \n0x10 POP \n0x11 PUSH1 0x04\n0x13 CALLDATASIZE \n0x14 LT \n0x15 PUSH1 0x30\n0x17 JUMPI \n",, I think the offeset 0x0f should be changed to 0x0e. As alessanromazza98 said, there is a one bit error in the offset.
I think the correct result should be something like this:
Image

Also, I am confused why there are the same offsets?

            15: "0x31 JUMPDEST \n0x32 PUSH0 0\n0x33 DUP1 \n0x34 REVERT \n",
            16: "0x31 JUMPDEST \n0x32 PUSH0 0\n0x33 DUP1 \n0x34 REVERT \n",

And the edge is not correct:

// (2, 16) is not correct
edges: (0, 1), (0, 2), (2, 3), (3, 4), (4, 5), (5, 6), (5, 7), (7, 8), (7, 9), (9, 10), (9, 11), (4, 12), (3, 13), (13, 14), (13, 15), (2, 16),

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-bug Type: bug
Projects
None yet
Development

No branches or pull requests

3 participants