Document intentional and unintentional unsigned integer overflows (wraparounds) using annotations #14224

pull practicalswift wants to merge 2 commits into bitcoin:master from practicalswift:no_sanitize-unsigned-integer-overflow changing 21 files +104 −59
  1. practicalswift commented at 9:27 AM on September 15, 2018: contributor
    • Add -fsanitize=integer Travis job
    • Document unsigned integer overflows (wraparounds) using annotation ALLOW_WRAPAROUND (intentional) or WARNING_UNINTENTIONAL_WRAPAROUND (unintentional).
  2. practicalswift renamed this:
    Annotate unsigned integer overflows. Add Travis job with -fsanitize=integer.
    Annotate unsigned integer overflows. Add -fsanitize=integer Travis job.
    on Sep 15, 2018
  3. fanquake added the label Refactoring on Sep 15, 2018
  4. fanquake added the label Tests on Sep 15, 2018
  5. ken2812221 commented at 9:46 AM on September 15, 2018: contributor

    Concept ACK.

  6. in .travis.yml:122 in c65df56f68 outdated
     123 | +        HOST=x86_64-unknown-linux-gnu
     124 | +        PACKAGES="clang python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev"
     125 | +        NO_DEPENDS=1
     126 | +        RUN_BENCH=false
     127 | +        UBSAN_OPTIONS="suppressions=../contrib/sanitizers-ubsan-integer.suppressions"
     128 | +        RUN_FUNCTIONAL_TESTS=false # Disabled for now, can be combined with the other x86_64 linux NO_DEPENDS job when functional tests pass the sanitizers
    


    ken2812221 commented at 9:48 AM on September 15, 2018:

    Can't we pass the functional tests with integer sanitizer even we suppress those cases?


    practicalswift commented at 2:44 PM on September 15, 2018:

    I got it working locally but not on Travis which is a bit weird. I'm still investigating – the intention is to run also the functional tests under the sanitizer :-)

  7. DrahtBot commented at 12:44 PM on September 15, 2018: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #14651 (Refactor: Fix compiler warning in prevector.h by ldm5180)
    • #14605 (Return of the Banman by dongcarl)
    • #14194 (Annotate unused parameters with [[maybe_unused]] by practicalswift)
    • #13949 (Introduce MempoolObserver interface to break "policy/fees -> txmempool -> policy/fees" circular dependency by Empact)
    • #13937 (Track best-possible-headers (TheBlueMatt) by Sjors)
    • #13864 (validation: Document where we are intentionally ignoring bool return values from validation related functions by practicalswift)
    • #13815 (util: Add [[nodiscard]] to all {Decode,Parse}... functions returning bool by practicalswift)
    • #13804 (WIP: Transaction Pool Layer by MarcoFalke)
    • #13062 (Make script interpreter independent from storage type CScript by sipa)
    • #11535 (Avoid unintentional unsigned integer wraparounds by practicalswift)
    • #10729 (Wrap EvalScript in a ScriptExecution class by luke-jr)
    • #10443 (Add fee_est tool for debugging fee estimation code by ryanofsky)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  8. DrahtBot cross-referenced this on Sep 15, 2018 from issue convert C-style (void) parameter lists to C++ style () by arvidn
  9. DrahtBot cross-referenced this on Sep 15, 2018 from issue Annotate unused parameters with [[maybe_unused]] by practicalswift
  10. DrahtBot cross-referenced this on Sep 15, 2018 from issue Use std::unordered_set instead of set in blockfilter interface by jimpo
  11. DrahtBot cross-referenced this on Sep 15, 2018 from issue Utxoscriptindex by mgrychow
  12. DrahtBot cross-referenced this on Sep 15, 2018 from issue Add tests and error handling to DecodeExtPubKey/DecodeExtKey. Add [[nodiscard]]. by practicalswift
  13. DrahtBot cross-referenced this on Sep 15, 2018 from issue validation: Document where we are intentionally ignoring bool return values from validation related functions by practicalswift
  14. DrahtBot cross-referenced this on Sep 15, 2018 from issue util: Add [[nodiscard]] to all {Decode,Parse}[...](...) functions returning bool by practicalswift
  15. DrahtBot cross-referenced this on Sep 15, 2018 from issue WIP: Transaction Pool Layer by MarcoFalke
  16. practicalswift force-pushed on Sep 15, 2018
  17. DrahtBot cross-referenced this on Sep 15, 2018 from issue WIP [bench] CCoinsView(Cache): measure various scenarios by Sjors
  18. practicalswift renamed this:
    Annotate unsigned integer overflows. Add -fsanitize=integer Travis job.
    Annotate unsigned integer overflows (wraparounds). Add -fsanitize=integer Travis job.
    on Sep 15, 2018
  19. arvidn commented at 2:42 AM on September 16, 2018: none

    there are a few #include<> directives that changed order, was that deliberate? I take it the idea is to make new code that relies on unsigned wrap-around semantics to be annotated, and current annotations to be removed as code is fixed. Is that right? would it make sense to use a different name for the macro? something like: ALLOW_WRAPAROUND.

    nit: technically unsigned integers don't overflow, all operators on unsigned have modulo-2 arithmetic, so all results will always fit in the resulting variable.

  20. practicalswift force-pushed on Sep 16, 2018
  21. practicalswift renamed this:
    Annotate unsigned integer overflows (wraparounds). Add -fsanitize=integer Travis job.
    Add -fsanitize=integer Travis job. Annotate unsigned integer overflows (wraparounds).
    on Sep 16, 2018
  22. practicalswift renamed this:
    Add -fsanitize=integer Travis job. Annotate unsigned integer overflows (wraparounds).
    Add -fsanitize=integer Travis job. Document unsigned integer overflows (wraparounds) using annotation ALLOW_WRAPAROUND.
    on Sep 16, 2018
  23. gmaxwell commented at 7:14 AM on September 16, 2018: contributor

    Please don't just blindly permit existing cases that might actually be bugs. If we must do this with bypasses, the annotation macro should be different for cases where the modular arithmetic is intentional (e.g. hash functions) and where we're just silencing the warning in order to get something merged.

  24. practicalswift commented at 7:18 AM on September 16, 2018: contributor

    @arvidn ALLOW_WRAPAROUND is a much better name. Updated!

    Yes, the include sorting was deliberate.

    Yes, the idea is to make it so that new code that relies on unsigned wrap-around semantics is annotated. I've now added the following to the developer notes to clarify:

    Do not rely on unsigned wrap-around semantics unless there are good reasons for doing so (e.g. hashing). Functions that rely on on unsigned wrap-around semantics should be annotated using ALLOW_WRAPAROUND.

    • Rationale: Code relying on unsigned wrap-around semantics is legal and well-defined but error-prone.

    Looks good?

  25. gmaxwell commented at 7:24 AM on September 16, 2018: contributor

    I don't agree that it is error prone. I'm aware of no study which shows as much, and it's not my experience that intentional use of modular arithmetic results in bugs.

    The comment should state that intentional use of it needs to be annotated because unintended wraps are often bugs and we use instrumentation to look for those bugs.

    But so long as the patch just papers over behaviour that is probably buggy-- or only not buggy by chance--, I think my position is NAK.

  26. practicalswift commented at 7:24 AM on September 16, 2018: contributor

    @gmaxwell The bulk of the existing ones were handled in #11535 which was submitted almost a year ago :-)

    My main goal with this PR is to make sure we're not introducing new unintentional integer wrap arounds. Until #11535 is merged I'm afraid we need ALLOW_WRAPAROUND to make -fsanitize=integer pass, no?

    Please advice on how to proceed :-)

  27. DrahtBot cross-referenced this on Sep 16, 2018 from issue Use MakeUnique to construct objects owned by unique_ptrs by practicalswift
  28. practicalswift commented at 7:27 AM on September 16, 2018: contributor

    @gmaxwell Yes, intentional use of wraparound semantics (e.g. hashing code) is obviously not problematic. I'll update the developer note to make that crystal clear.

  29. practicalswift commented at 7:36 AM on September 16, 2018: contributor

    @gmaxwell

    I don't agree that it is error prone. I'm aware of no study which shows as much

    From the paper "Understanding Integer Overflow in C/C++" co-authored by Regehr:

    IOC’s instrumentation is designed to be semantically transparent for programs that conform to the C or C++ language standards, except in the case where a user requests additional checking for conforming but error-prone operations, e.g., wraparound with unsigned integer types.

    .-)

  30. practicalswift force-pushed on Sep 16, 2018
  31. practicalswift force-pushed on Sep 16, 2018
  32. practicalswift force-pushed on Sep 16, 2018
  33. practicalswift force-pushed on Sep 16, 2018
  34. practicalswift commented at 1:04 PM on September 16, 2018: contributor

    @arvidn @gmaxwell Thanks for reviewing. I've now updated the developer notes and split the annotations in two as suggested by @gmaxwell: ALLOW_WRAPAROUND for intentional wraparounds and WARNING_UNINTENTIONAL_WRAPAROUND for unintentional wraparounds.

    Could you please re-review? :-)

    These are the intentional wraparounds:

    $ git grep ALLOW_WRAPAROUND -- "*.cpp" "*.h" ":(exclude)src/attributes.h"
    src/bloom.cpp:ALLOW_WRAPAROUND static inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, const std::vector<unsigned char>& vDataToHash) {
    src/crypto/chacha20.cpp:ALLOW_WRAPAROUND void ChaCha20::Output(unsigned char* c, size_t bytes)
    src/crypto/ripemd160.cpp:ALLOW_WRAPAROUND void inline Round(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t f, uint32_t x, uint32_t k, int r)
    src/crypto/ripemd160.cpp:ALLOW_WRAPAROUND void Transform(uint32_t* s, const unsigned char* chunk)
    src/crypto/sha1.cpp:ALLOW_WRAPAROUND void inline Round(uint32_t a, uint32_t& b, uint32_t c, uint32_t d, uint32_t& e, uint32_t f, uint32_t k, uint32_t w)
    src/crypto/sha1.cpp:ALLOW_WRAPAROUND void Transform(uint32_t* s, const unsigned char* chunk)
    src/crypto/sha256.cpp:ALLOW_WRAPAROUND void inline Round(uint32_t a, uint32_t b, uint32_t c, uint32_t& d, uint32_t e, uint32_t f, uint32_t g, uint32_t& h, uint32_t k)
    src/crypto/sha256.cpp:ALLOW_WRAPAROUND void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)
    src/crypto/sha512.cpp:ALLOW_WRAPAROUND void inline Round(uint64_t a, uint64_t b, uint64_t c, uint64_t& d, uint64_t e, uint64_t f, uint64_t g, uint64_t& h, uint64_t k, uint64_t w)
    src/crypto/sha512.cpp:ALLOW_WRAPAROUND void Transform(uint64_t* s, const unsigned char* chunk)
    src/hash.cpp:ALLOW_WRAPAROUND unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash)
    src/hash.cpp:ALLOW_WRAPAROUND CSipHasher& CSipHasher::Write(uint64_t data)
    src/hash.cpp:ALLOW_WRAPAROUND CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size)
    src/hash.cpp:ALLOW_WRAPAROUND uint64_t CSipHasher::Finalize() const
    src/hash.cpp:ALLOW_WRAPAROUND uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
    src/hash.cpp:ALLOW_WRAPAROUND uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
    

    These are the unintentional wraparounds:

    $ git grep WARNING_UNINTENTIONAL_WRAPAROUND -- "*.cpp" "*.h" ":(exclude)src/attributes.h"
    src/arith_uint256.h:    WARNING_UNINTENTIONAL_WRAPAROUND base_uint& operator++()
    src/bench/bench.h:    WARNING_UNINTENTIONAL_WRAPAROUND inline bool KeepRunning()
    src/chain.cpp:WARNING_UNINTENTIONAL_WRAPAROUND int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
    src/chain.h:    WARNING_UNINTENTIONAL_WRAPAROUND int Height() const {
    src/core_write.cpp:WARNING_UNINTENTIONAL_WRAPAROUND std::string FormatScript(const CScript& script)
    src/policy/fees.cpp:WARNING_UNINTENTIONAL_WRAPAROUND double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
    src/prevector.h:    WARNING_UNINTENTIONAL_WRAPAROUND reverse_iterator rbegin() { return reverse_iterator(item_ptr(size() - 1)); }
    src/prevector.h:    WARNING_UNINTENTIONAL_WRAPAROUND const_reverse_iterator rbegin() const { return const_reverse_iterator(item_ptr(size() - 1)); }
    src/script/interpreter.cpp:WARNING_UNINTENTIONAL_WRAPAROUND bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
    src/txmempool.cpp:WARNING_UNINTENTIONAL_WRAPAROUND void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors)
    src/txmempool.cpp:WARNING_UNINTENTIONAL_WRAPAROUND void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
    src/txmempool.cpp:WARNING_UNINTENTIONAL_WRAPAROUND void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps)
    src/utilstrencodings.cpp:WARNING_UNINTENTIONAL_WRAPAROUND void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
    src/validation.cpp:WARNING_UNINTENTIONAL_WRAPAROUND DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view)
    src/validation.cpp:WARNING_UNINTENTIONAL_WRAPAROUND bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
    src/validation.cpp:WARNING_UNINTENTIONAL_WRAPAROUND bool LoadMempool(void)
    

    Looks correct? :-)

  35. practicalswift renamed this:
    Add -fsanitize=integer Travis job. Document unsigned integer overflows (wraparounds) using annotation ALLOW_WRAPAROUND.
    Add -fsanitize=integer Travis job. Document unsigned integer overflows (wraparounds) using annotation ALLOW_WRAPAROUND (intentional) or WARNING_UNINTENTIONAL_WRAPAROUND (unintentional).
    on Sep 16, 2018
  36. practicalswift renamed this:
    Add -fsanitize=integer Travis job. Document unsigned integer overflows (wraparounds) using annotation ALLOW_WRAPAROUND (intentional) or WARNING_UNINTENTIONAL_WRAPAROUND (unintentional).
    Add -fsanitize=integer Travis job. Document intentional and unintentional unsigned integer overflows (wraparounds) using annotations.
    on Sep 16, 2018
  37. practicalswift force-pushed on Sep 17, 2018
  38. practicalswift force-pushed on Sep 17, 2018
  39. practicalswift commented at 12:29 PM on September 17, 2018: contributor

    @ken2812221 Now running also the functional tests and the quick bench test. Please re-review :-)

  40. practicalswift force-pushed on Sep 17, 2018
  41. in doc/developer-notes.md:450 in 9ce5e11584 outdated
     438 | @@ -439,6 +439,14 @@ General C++
     439 |  
     440 |    - *Rationale*: This avoids memory and resource leaks, and ensures exception safety
     441 |  
     442 | +- Do not rely on unsigned wrap-around semantics unless there are good reasons for doing so (e.g. hash functions).
     443 | +  Functions that intentionally rely on unsigned wrap-around semantics should be annotated using `ALLOW_WRAPAROUND`.
     444 | +  Functions that unintentionally trigger unsigned wrap-arounds should be annotated using
     445 | +  `WARNING_UNINTENTIONAL_WRAPAROUND` while awaiting being fixed.
    


    arvidn commented at 2:37 PM on September 17, 2018:

    would it be unrealistic to fix all these before landing this patch, so this annotation is not needed?


    practicalswift commented at 2:49 PM on September 17, 2018:

    @arvidn My main goal with this PR is to make it less likely that we introduce new unintentional wraparounds going forward, so I'll choose the quickest route to get this checked by Travis.

    The progress in #11535 which fixes these cases has been quite slow during the last year, so perhaps it would make sense to first get this PR merged and then take on fixing WARNING_UNINTENTIONAL_WRAPAROUND? That way we get the much needed Travis checking sooner rather than later :-)

  42. DrahtBot cross-referenced this on Sep 18, 2018 from issue build: Run functional tests and benchmarks under the undefined behaviour sanitizer (UBSan) by practicalswift
  43. DrahtBot cross-referenced this on Sep 18, 2018 from issue build: Add address sanitizer (ASan) Travis job by practicalswift
  44. DrahtBot added the label Needs rebase on Sep 20, 2018
  45. practicalswift force-pushed on Sep 21, 2018
  46. practicalswift renamed this:
    Add -fsanitize=integer Travis job. Document intentional and unintentional unsigned integer overflows (wraparounds) using annotations.
    Document intentional and unintentional unsigned integer overflows (wraparounds) using annotations
    on Sep 21, 2018
  47. practicalswift force-pushed on Sep 21, 2018
  48. practicalswift force-pushed on Sep 21, 2018
  49. DrahtBot removed the label Needs rebase on Sep 21, 2018
  50. practicalswift commented at 1:06 PM on September 21, 2018: contributor

    I've now changed this PR to only add annotations.

    The Travis checking is added in #14252 independently of the annotations.

    Also rebased.

  51. DrahtBot cross-referenced this on Sep 21, 2018 from issue tests: Use MakeUnique to construct objects owned by unique_ptrs by practicalswift
  52. DrahtBot cross-referenced this on Sep 21, 2018 from issue Make script interpreter independent from storage type CScript by sipa
  53. DrahtBot cross-referenced this on Sep 21, 2018 from issue Avoid unintentional unsigned integer wraparounds by practicalswift
  54. DrahtBot cross-referenced this on Sep 21, 2018 from issue Add fee_est tool for debugging fee estimation code by ryanofsky
  55. DrahtBot added the label Needs rebase on Sep 21, 2018
  56. practicalswift force-pushed on Sep 22, 2018
  57. DrahtBot removed the label Needs rebase on Sep 22, 2018
  58. practicalswift force-pushed on Sep 30, 2018
  59. DrahtBot cross-referenced this on Oct 3, 2018 from issue Fire TransactionRemovedFromMempool callbacks from mempool by l2a5b1
  60. practicalswift cross-referenced this on Oct 4, 2018 from issue fix assert crash when specified change output spend size is unknown by instagibbs
  61. DrahtBot cross-referenced this on Oct 23, 2018 from issue Move util files to directory by jimpo
  62. DrahtBot cross-referenced this on Oct 30, 2018 from issue Return of the Banman by dongcarl
  63. DrahtBot cross-referenced this on Oct 30, 2018 from issue Track best-possible-headers (TheBlueMatt) by Sjors
  64. DrahtBot added the label Needs rebase on Nov 5, 2018
  65. practicalswift force-pushed on Nov 5, 2018
  66. DrahtBot removed the label Needs rebase on Nov 5, 2018
  67. practicalswift force-pushed on Nov 5, 2018
  68. practicalswift force-pushed on Nov 5, 2018
  69. DrahtBot added the label Needs rebase on Nov 6, 2018
  70. practicalswift force-pushed on Nov 6, 2018
  71. DrahtBot removed the label Needs rebase on Nov 6, 2018
  72. bitcoin deleted a comment on Nov 6, 2018
  73. bitcoin deleted a comment on Nov 6, 2018
  74. bitcoin deleted a comment on Nov 6, 2018
  75. bitcoin deleted a comment on Nov 6, 2018
  76. bitcoin deleted a comment on Nov 6, 2018
  77. DrahtBot added the label Needs rebase on Nov 12, 2018
  78. Document unsigned integer wraparounds with ALLOW_WRAPAROUND (intentional) or WARNING_UNINTENTIONAL_WRAPAROUND (unintentional) c1c726efb8
  79. Add developer note about ALLOW_WRAPAROUND 0373038ced
  80. practicalswift force-pushed on Nov 12, 2018
  81. DrahtBot removed the label Needs rebase on Nov 12, 2018
  82. practicalswift closed this on Nov 12, 2018

  83. practicalswift cross-referenced this on Dec 4, 2018 from issue Stricter & More Performant Invariant Checking in CheckBlock by JeremyRubin
  84. practicalswift deleted the branch on Apr 10, 2021
  85. bitcoin 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-05-20 06:54 UTC