smlxl / storage-layout-extractor

A tool that performs extraction of storage layouts based on EVM bytecode.
https://smlxl.io
GNU Affero General Public License v3.0
132 stars 11 forks source link

[BUG] `Bytes` with length 0 #105

Closed 2xic closed 1 year ago

2xic commented 1 year ago

Describe the Bug

Sometimes we see types with length 0

To Reproduce

Run BlitzGenerator

Output for slot 0x000000000000000000000000000000000000000000000000000000000000000e

  {
    "index": "0x000000000000000000000000000000000000000000000000000000000000000e",
    "offset": 0,
    "type": {
      "mapping": {
        "key_type": {
          "u_int": {
            "size": 256
          }
        },
        "value_type": {
          "struct": {
            "elements": [
              {
                "offset": 0,
                "type": {
                  "u_int": {
                    "size": null
                  }
                }
              },
              {
                "offset": 256,
                "type": {
                  "u_int": {
                    "size": 256
                  }
                }
              },
              {
                "offset": 512,
                "type": {
                  "u_int": {
                    "size": 256
                  }
                }
              },
              {
                "offset": 768,
                "type": {
                  "u_int": {
                    "size": 256
                  }
                }
              },
              {
                "offset": 1024,
                "type": {
                  "u_int": {
                    "size": null
                  }
                }
              },
              {
                "offset": 1280,
                "type": "any"
              },
              {
                "offset": 3840,
                "type": {
                  "bytes": {
                    "length": 0 // length 0
                  }
                }
              },
              {
                "offset": 3841,
                "type": {
                  "u_int": {
                    "size": 7
                  }
                }
              },
              {
                "offset": 4096,
                "type": {
                  "bytes": {
                    "length": 1
                  }
                }
              },
              {
                "offset": 4104,
                "type": {
                  "bytes": {
                    "length": 31
                  }
                }
              }
            ]
          }
        }
      }
    }
  },

Expected Behaviour

Bits length have been used for data types like uint and int. So maybe seeing that here also.

iamrecursion commented 1 year ago

This happens because internally the analyzer records the length of all types in bits. It is perfectly valid at the EVM level to see a value that has length % BYTE_SIZE != 0 that is only ever used as bytes.

When converting to BytesN in the output stage, we just calculate bit_length / BYTE_SIZE, which when bit_length < BYTE_SIZE rounds to 0 bytes and produces this strange output.

As these lengths that are not divisible by BYTE_SIZE are correct at the machine level, we should introduce AbiType::Bits { length: Option<usize> } for these cases, and thus leave the choice of how to handle this for users up to the CLI.