Signbugs #1298

pull wizeman wants to merge 8 commits into bitcoin:master from wizeman:signbugs changing 6 files +148 −9
  1. wizeman commented at 3:33 PM on May 14, 2012: contributor

    This pull request has fixes to prevent bit shifting signed integers to the left, onto and past the sign bit.

    While this currently does not cause problems, it is undefined behavior in C++11 and could cause problems in the future (i.e. so-called time bombs). Bitcoin in particular should be extra careful about these problems.

  2. Make CNetAddr::GetHash() return an unsigned val.
    This prevents an undefined operation in main.cpp, when shifting the hash value
    left by 32 bits.
    Shifting a signed int left into the sign bit is undefined in C++11.
    4843b55fd1
  3. Don't overflow signed ints in CBigNum::setint64().
    CBigNum::setint64() does 'n <<= 8', where n is of type "long long".
    
    This leads to shifting onto and past the sign bit, which is undefined
    behavior in C++11 and can cause problems in the future.
    fe78c9ae8b
  4. gavinandresen commented at 3:42 PM on May 14, 2012: contributor

    How did you test these changes?

  5. wizeman commented at 3:54 PM on May 14, 2012: contributor

    For commit "4843b55 Make CNetAddr::GetHash() return an unsigned val.", I verified that there was only one user of CNetAddr::GetHash() by changing the return value to 'void' and seeing where the compilation broke.

    In the single user of that function, I think the changes are relatively straightforward and the hash calculations more likely to be correct using uint64 than int64.

    For commit "fe78c9a Don't overflow signed ints in CBigNum::setint64()", I wrote a small program that tested creating a few CBigNum vars, with positive and negative integers, to make sure the results were the ones expected.

    These 2 bugs were detected using a tool that automatically detects some kinds of undefined behavior at run-time. After fixing them, no more errors were reported.

    Furthermore, I let bitcoind run with that tool, along with another one which detects memory corruption problems (even more kinds of memory corruption than valgrind is able to detect), while confirming the latest ~150 blocks of the main net. It successfully confirmed them without any apparent problems.

  6. gavinandresen commented at 6:04 PM on May 14, 2012: contributor

    Could you turn your small test program into unit tests in src/test/bignum_tests.cpp ? Comments on where to get your nifty testing tools/methods would be most welcome, too (in that does-not-exist-yet unit test file).

  7. Add test case for CBigNum::setint64().
    One of the test cases currently aborts when using gcc's flag -ftrapv, due to
    negating an INT64_MIN int64 variable, which is an undefined operation.
    
    This will be fixed in a subsequent commit.
    62e0453ce0
  8. Fix signed subtraction overflow in CBigNum::setint64().
    As noticed by sipa (Pieter Wuille), this can happen when CBigNum::setint64() is
    called with an integer value of INT64_MIN (-2^63).
    
    When compiled with -ftrapv, the program would crash. Otherwise, it would
    execute an undefined operation (although in practice, usually the correct one).
    5849bd472a
  9. wizeman commented at 7:39 PM on May 14, 2012: contributor

    I added test cases for CBigNum::setint64(). It was a bit more complex than I thought because gcc (with -O2) was inlining the function and, due to the values being constants, optimizing it to the point that -ftrapv was not detecting the signed subtraction overflow when the function was given an INT64_MIN argument.

    After the test case was added, it was aborting in one of the test cases, as expected, due to the mentioned bug.

    The commit "5849bd4 Fix signed subtraction overflow in CBigNum::setint64()" then fixes the bug.

    Note that this bug is also present in the mainline bitcoin code and will cause bitcoin to crash when a CBigNum var is initialized with an INT64_MIN value and the code was compiled with -ftrapv.

  10. Fix noinline definition so that it works for more compilers. 78e851f94f
  11. Use C++-style numeric limits instead of C-style. 10b45b4c2e
  12. in src/test/bignum_tests.cpp:None in 5849bd472a outdated
       0 | @@ -0,0 +1,110 @@
       1 | +#include <boost/test/unit_test.hpp>
       2 | +#include <climits>
    


    gavinandresen commented at 6:40 PM on May 29, 2012:

    The rest of the code uses #include <limits> and std::numeric_limits<type>::min()/max(), it'd be nice to be consistent if possible.

  13. in src/test/bignum_tests.cpp:None in 5849bd472a outdated
      27 | +// stack buffer overruns, which valgrind can't currently detect.
      28 | +
      29 | +// Let's force this code not to be inlined, in order to actually
      30 | +// test a generic version of the function. This increases the chance
      31 | +// that -ftrapv will detect overflows.
      32 | +void mysetint64(CBigNum& num, int64 n) __attribute__((noinline));
    


    gavinandresen commented at 6:42 PM on May 29, 2012:

    attribute is gcc only, we should try to stay compiler-independent as much as possible.

  14. wizeman commented at 6:41 PM on May 31, 2012: contributor

    Thanks for the numeric limits suggestion, I was not aware of that (I'm a lot more experienced in C than C++, as you can probably guess). I have fixed that as you suggested.

    As for the noinline attribute, it will work on any compiler that supports gcc extensions (it should work for gcc, clang and icc, at least), but I guess not for MSVC++.

    As far as I could find out, there is no standard way of doing this, so we just have to use whatever syntax each compiler supports.

    I have updated the code to define a NOINLINE macro which will conditionally use syntax for gcc-compatible compilers (gcc, clang, icc), MSVC++ or emit a warning if the code is being compiled with an unknown compiler.

    I have re-tested everything with gcc and clang (with and without the fix, to see if the test still works), but I haven't tested with MSVC++ as I don't have access to such an environment at the moment.

  15. Don't overflow integer on 32-bit machines.
    This was causing test_bitcoin to abort on a 32-bit system likely due to -ftrapv.
    43346904e1
  16. Move NOINLINE definition to test where it's used. 31ac53fbdc
  17. in src/util.h:None in 10b45b4c2e outdated
      42 | @@ -43,6 +43,23 @@
      43 |  #define ARRAYLEN(array)     (sizeof(array)/sizeof((array)[0]))
      44 |  #define printf              OutputDebugStringF
      45 |  
      46 | +// Unfortunately there's no standard way of preventing a function from being
      47 | +// inlined, so we define a macro for it.
    


    gavinandresen commented at 1:51 PM on June 5, 2012:

    In my opinion, this mess should go in bignum_tests.cpp, since that's the only place it is used and I can't imagine we'll use it anyplace else.

  18. wizeman commented at 9:37 PM on June 7, 2012: contributor

    I've moved the NOINLINE definition to the test rather than util.h, as suggested.

    I have also fixed a bug which was causing the test_bitcoin program to abort on 32-bit systems.

  19. sipa commented at 7:35 PM on June 12, 2012: member

    ACK (needs a trivial rebase though).

  20. wizeman commented at 9:09 PM on June 13, 2012: contributor

    So what is the process now?

    Should I rebase? If so, can I do it in the same branch, and will the pull request preserve all existing information?

  21. gavinandresen merged this on Jun 18, 2012
  22. gavinandresen closed this on Jun 18, 2012

  23. sipa commented at 2:53 PM on June 18, 2012: member

    @wizeman Seems @gavinandresen did it for you.

    For future reference: yes, you can just push to the branch on github where you originally pullrequested from, and the pull request will be updated accordingly (keeping relevant discussion, but changing commits as necessary).

  24. wizeman commented at 2:54 PM on June 18, 2012: contributor

    Cool, thanks to both of you!

  25. luke-jr commented at 3:17 AM on July 11, 2012: member

    @wizeman Could you comment on #1497 please?

  26. wizeman commented at 6:41 AM on July 11, 2012: contributor

    Hi luke-jr,

    I added a comment to your pull request.

    Cheers, Ricardo

  27. suprnurd referenced this in commit c8466cfb04 on Dec 5, 2017
  28. lateminer referenced this in commit e696997271 on Jan 22, 2019
  29. lateminer referenced this in commit 5dfad15c57 on May 6, 2020
  30. DrahtBot locked this on Sep 8, 2021

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-14 18:16 UTC

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