foundry icon indicating copy to clipboard operation
foundry copied to clipboard

`stdJson.parseUintArray / stdJson.parseRaw`: uints in an array that are >= `1e20` will crash the JSON encoder and cause a panic

Open kryptoklob opened this issue 2 years ago • 3 comments

Component

Forge

Have you ensured that all of these are up to date?

  • [X] Foundry
  • [X] Foundryup

What version of Foundry are you on?

forge 0.2.0 (c2816ca 2022-09-14T00:12:29.080011374Z)

What command(s) is the bug in?

forge test

Operating System

Linux

Describe the bug

TLDR: When parsing arrays of uints via stdJson.parseRaw (and also via stdJson.parseUintArray), any numbers equal to or higher than 1e20 will cause a panic.

While this can be solved by quoting the numbers, we must then use parseStringArray (or just decode it to a string array), and then decode it from the ascii-encoded hex representation before we can get back to an array of uints; we cannot directly decode it to a uint array (because they get encoded as string/ascii representation by the JSON parser when they are quoted).

Proof of concept below. Note that if I remove the last entry from the "test" array below, the code works fine.

testNumbers.json:

{
    "test": [
        10000000000,
        100000000000,
        1000000000000,
        10000000000000,
        100000000000000,
        1000000000000000,
        10000000000000000,
        100000000000000000,
        1000000000000000000,
        10000000000000000000,
        100000000000000000000
    ]
}
testParsingNumbers.t.sol

pragma solidity ^0.8.15;

import {Test} from "../../../libs/forge-standard/src/Test.sol";
import {console2} from "../../../libs/forge-standard/src/console2.sol";
import {stdJson} from "../../../libs/forge-standard/src/StdJson.sol";

contract TestNumberParsing is Test {
    using stdJson for string;

    function setUp() public {

        string memory root = "/home/caleb/fei-protocol-core";
        string memory path = string.concat(root, "/proposals/data/merkle_redeemer/testNumbers.json");
        string memory json = vm.readFile(path);

        bytes memory processed = stdJson.parseRaw(json, ".test");

        console2.log(processed.length);
    }

    function test() public {
        console2.log('Random text so this test actually runs.');
    }
}
❯ RUST_BACKTRACE=1 forge test --match-contract TestNumberParsing -vvvv

The application panicked (crashed).
Message:  called `Result::unwrap()` on an `Err` value: String("Could not decode field")
Location: evm/src/executor/inspector/cheatcodes/ext.rs:303

This is a bug. Consider reporting it at https://github.com/foundry-rs/foundry

  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   1: start_thread<unknown>
      at <unknown source file>:<unknown line>
   2: clone<unknown>
      at <unknown source file>:<unknown line>

Run with COLORBT_SHOW_HIDDEN=1 environment variable to disable frame filtering.
Run with RUST_BACKTRACE=full to include source snippets.
zsh: abort      RUST_BACKTRACE=1 forge test --match-contract TestNumberParsing -vvvv

kryptoklob avatar Sep 14 '22 13:09 kryptoklob

Tagging @odyslam as I know you were the one to add this feature (which is fantastic, by the way, thank you!)

kryptoklob avatar Sep 14 '22 13:09 kryptoklob

thanks for the repro, we should be able to fix that, checking

mattsse avatar Sep 14 '22 13:09 mattsse

there's nothing we can do here unfortunately,

while json spec doesn't define number boundaries, serde_json limits them to u64::MAX,

would recommend using hex format for larger values (U256)

however we need to gracefully handle the panic here

mattsse avatar Sep 14 '22 19:09 mattsse

Closing per the above comment, and this should be resolved now with recent parseJson updates/fixes

mds1 avatar Mar 09 '23 23:03 mds1