Invalid integer negation in FormatMoney(CAmount n) and ValueFromAmount (CAmount n) when n = std::numeric_limits<CAmount>::min() #20402

issue practicalswift opened this issue on November 16, 2020
  1. practicalswift commented at 3:32 PM on November 16, 2020: contributor

    FormatMoney(CAmount n) is not being properly defined for n = std::numeric_limits<CAmount>::min(). This is due to an invalid integer negation: the negation of -9223372036854775808 cannot be represented in type CAmount (which has a max value of 9223372036854775807):

    https://github.com/bitcoin/bitcoin/blob/54f812d9d29893c690ae06b84aaeab128186aa36/src/util/moneystr.cpp#L12-L31

    FWIW FormatMoney(-9223372036854775808) returns --92233720368.-54775808 when compiled with UBSan (LLVM/Clang, -fsanitize=undefined).

    Context: #20383 (review)

    It would be nice if FormatMoney(CAmount n) was properly defined for all CAmount n :)

    These are the "expectations of least surprise":

    BOOST_CHECK_EQUAL(FormatMoney(std::numeric_limits<CAmount>::max()), "92233720368.54775807");       //  9223372036854775807
    BOOST_CHECK_EQUAL(FormatMoney(std::numeric_limits<CAmount>::max() - 1), "92233720368.54775806");   //  9223372036854775806
    BOOST_CHECK_EQUAL(FormatMoney(std::numeric_limits<CAmount>::max() - 2), "92233720368.54775805");   //  9223372036854775805
    BOOST_CHECK_EQUAL(FormatMoney(std::numeric_limits<CAmount>::max() - 3), "92233720368.54775804");   //  9223372036854775804
    BOOST_CHECK_EQUAL(FormatMoney(std::numeric_limits<CAmount>::min() + 3), "-92233720368.54775805");  // -9223372036854775805
    BOOST_CHECK_EQUAL(FormatMoney(std::numeric_limits<CAmount>::min() + 2), "-92233720368.54775806");  // -9223372036854775806
    BOOST_CHECK_EQUAL(FormatMoney(std::numeric_limits<CAmount>::min() + 1), "-92233720368.54775807");  // -9223372036854775807
    BOOST_CHECK_EQUAL(FormatMoney(std::numeric_limits<CAmount>::min()), "-92233720368.54775808");      // -9223372036854775808
    

    These assertions are guaranteed to hold for all cases above except for the last one.

  2. practicalswift renamed this:
    Invalid integer negation in FormatMoney(CAmount n) when n == std::numeric_limits<CAmount>::min()
    Invalid integer negation in FormatMoney(CAmount n) when n = std::numeric_limits<CAmount>::min()
    on Nov 16, 2020
  3. practicalswift commented at 4:25 PM on November 16, 2020: contributor

    I think we have exactly the same small problem for UniValue ValueFromAmount(const CAmount& amount).

    It needs the same fix :)

  4. practicalswift renamed this:
    Invalid integer negation in FormatMoney(CAmount n) when n = std::numeric_limits<CAmount>::min()
    Invalid integer negation in FormatMoney(CAmount n) and ValueFromAmount (CAmount n) when n = std::numeric_limits<CAmount>::min()
    on Nov 16, 2020
  5. practicalswift commented at 2:54 PM on December 2, 2020: contributor

    When fuzzing the RPC interface I stumbled upon this case again: decoderawtransaction ff0000000001000000000000008004ff0400fffe001f00 will trigger the problematic code path :)

    $ git checkout master
    $ CC=clang CXX=clang++ ./configure --with-sanitizers=address,undefined
    $ make
    $ src/bitcoind &
    $ src/bitcoin-cli decoderawtransaction ff0000000001000000000000008004ff0400fffe001f00
    core_write.cpp:21:29: runtime error: negation of -9223372036854775808 cannot be represented in type 'CAmount' (aka 'long'); cast to an unsigned type to negate this value to itself
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior core_write.cpp:21:29 in
    error: couldn't parse reply from server
    
  6. practicalswift commented at 3:11 PM on December 2, 2020: contributor

    The JSON response by the Bitcoin Core RPC interface:

    {
       "result" : {
          "size" : 23,
          "txid" : "cc0e5ecf6a06e4587bd011770c3ea4ceab58e86a234dd049ea3a27fab6fccfaa",
          "locktime" : 2031870,
          "hash" : "cc0e5ecf6a06e4587bd011770c3ea4ceab58e86a234dd049ea3a27fab6fccfaa",
          "vsize" : 23,
          "weight" : 92,
          "vout" : [
             {
                "scriptPubKey" : {
                   "hex" : "ff0400ff",
                   "asm" : "OP_INVALIDOPCODE [error]",
                   "type" : "nonstandard"
                },
                "n" : 0,
                "value" : --92233720368.-54775808
             }
          ],
          "version" : 255,
          "vin" : []
       },
       "error" : null,
       "id" : 1
    }
    

    Notice the malformed result.vout[0].value field (--92233720368.-54775808) :)

  7. laanwj closed this on Mar 3, 2021

  8. DrahtBot locked this on Aug 18, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-16 15:14 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me