ethereum / solidity

Solidity, the Smart Contract Programming Language
https://soliditylang.org
GNU General Public License v3.0
23.07k stars 5.72k forks source link

AbiCoder v1 incorrectly encodes arrays containing overflow values #14985

Open Subway2023 opened 5 months ago

Subway2023 commented 5 months ago

Description

When using assembly statements to assign a value that exceeds the array range to an array, AbiCoder v1 fails to encode the return value correctly when returning the array. However, AbiCoder v2 does not have this issue.

Environment

Steps to Reproduce

# If you comment out this line, AbiCoder v2 will be used by default.
pragma abicoder v1;
contract test {
    function f() external returns (uint8[] memory) {
        uint8[] memory x = new uint8[](1);
        assembly {
            mstore(add(x, 0x20), 0x1ff)
        }
        return x;
    }
}

1. Build EVM

git clone git@github.com:ethereum/go-ethereum.git
make all

2. Get function Signatures

solc C.sol --hashes --overwrite -o hashDir
Function signatures:
26121ff0: f()

3. Get bin-runtime

solc  --bin-runtime C.sol --overwrite -o binDir
608060405234801561000f575f80fd5b5060043610610029575f3560e01c806326121ff01461002d575b5f80fd5b61003561004b565b604051610042919061016c565b60405180910390f35b60605f600167ffffffffffffffff8111156100695761006861018c565b5b6040519080825280602002602001820160405280156100975781602001602082028036833780820191505090505b5090506101ff60208201528091505090565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f60ff82169050919050565b6100e7816100d2565b82525050565b5f6100f883836100de565b60208301905092915050565b5f602082019050919050565b5f61011a826100a9565b61012481856100b3565b935061012f836100c3565b805f5b8381101561015f57815161014688826100ed565b975061015183610104565b925050600181019050610132565b5085935050505092915050565b5f6020820190508181035f8301526101848184610110565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffdfea26469706673582212205a42b50705af3aa5760eee8c6f23424d2e988432726970a1c5cf3ed9a0111a6064736f6c63430008190033

4. Run in the EVM

go-ethereum-1.13.11/build/bin/evm --debug --json --code "bin in binDir" --input 26121ff0 run >test.json

5. Compare output

output from pragma abicoder v1

{"output":"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001ff","gasUsed":"0x23e"}

output from pragma abicoder v2

{"output":"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000ff","gasUsed":"0x3c9"}

We can observe that after encoding with AbiCoder v1, the elements in the array are 1ff, whereas after encoding with AbiCoder v2, the array elements are ff

Saw-mon-and-Natalie commented 4 months ago

Basically abicoder v1 does not clean the dirty bits in the first element of the array upon returning but abicoder v2 does. Also reproduced using 0.8.19+commit.7dd6d404.