util: Don’t derive secure_allocator from std::allocator #27930

pull CaseyCarter wants to merge 1 commits into bitcoin:master from CaseyCarter:master changing 2 files +39 −36
  1. CaseyCarter commented at 0:18 am on June 22, 2023: contributor

    Giving the C++ Standard Committee control of the public interface of your type means they will break it. C++23 adds a new allocate_at_least member to std::allocator. Very bad things happen when, say, std::vector uses allocate_at_least from secure_allocator’s base to allocate memory which it then tries to free with secure_allocator::deallocate.

    (Discovered by microsoft/STL#3712, which will be reverted by microsoft/STL#3819 before it ships.)

  2. DrahtBot commented at 0:18 am on June 22, 2023: contributor

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

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK john-moffett, jonatack, achow101
    Concept ACK jamesob

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

  3. DrahtBot added the label CI failed on Jun 22, 2023
  4. DrahtBot removed the label CI failed on Jun 22, 2023
  5. DrahtBot renamed this:
    Don't derive secure_allocator from std::allocator
    util: Don't derive secure_allocator from std::allocator
    on Jun 22, 2023
  6. DrahtBot added the label Utils/log/libs on Jun 22, 2023
  7. in src/support/allocators/secure.h:59 in 0a46196007 outdated
    54+        return true;
    55+    }
    56+    template <typename U>
    57+    friend bool operator!=(const secure_allocator&, const secure_allocator<U>&) noexcept
    58+    {
    59+        return true;
    


    frederick-vs-ja commented at 7:41 am on June 22, 2023:

    This look likes a copy-pasta.

    0        return false;
    

    CaseyCarter commented at 4:25 pm on June 22, 2023:
    Thanks!
  8. dergoegge commented at 10:04 am on June 22, 2023: member

    Thanks for the PR and raising the issue!

    I suspect that it’ll be a long time before binaries using C++23 would be shipped but this brings up a wider issue: like you say “giving the C++ Standard Committee control of the public interface” might not be a great idea.

    I’m guessing we should consider doing the same for zero_after_free_allocator? Even though it doesn’t seem to be affected by this particular issue.

    From https://github.com/microsoft/STL/pull/3819:

    https://github.com/microsoft/STL/pull/3712 broke BitCoin in Microsoft’s internal Real World Code (RWC) test suite.

    I’d be curious to know how this was actually caught? Compiling with c++23 and then running our tests with/without sanitizers?


    @theuni @ryanofsky any thoughts?

  9. CaseyCarter commented at 4:35 pm on June 22, 2023: contributor

    I’m guessing we should consider doing the same for zero_after_free_allocator? Even though it doesn’t seem to be affected by this particular issue.

    That’s probably a good idea, yes.

    From microsoft/STL#3819:

    microsoft/STL#3712 broke BitCoin in Microsoft’s internal Real World Code (RWC) test suite.

    I’d be curious to know how this was actually caught? Compiling with c++23 and then running our tests with/without sanitizers?

    Yes, we (MSVC) have a suite of a few dozen open-source projects that we use to validate by building and testing them in various configurations. One of your tests using this allocator with std::vector crashed (unsurprisingly) trying to deallocate memory.

  10. in src/support/allocators/secure.h:32 in bd5f9b96aa outdated
    28@@ -29,7 +29,7 @@ struct secure_allocator {
    29     template <typename Other>
    30     struct rebind {
    31         typedef secure_allocator<Other> other;
    32-    };
    33+    };g
    


    achow101 commented at 5:09 pm on June 22, 2023:
    Typo?

    CaseyCarter commented at 5:22 pm on June 22, 2023:
    :sigh: I’m really on fire with this PR.
  11. DrahtBot added the label CI failed on Jun 22, 2023
  12. DrahtBot removed the label CI failed on Jun 22, 2023
  13. maflcko commented at 7:25 am on June 23, 2023: member
    Please keep your commits squashed according to https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md#squashing-commits. This makes review easier, because reviewers will only need to look at one commit, and also is history cleaner because there will be less churn. (Note that we don’t squash on merge, so a squash will need to be done before review, before merge)
  14. CaseyCarter force-pushed on Jun 23, 2023
  15. CaseyCarter commented at 2:40 pm on June 23, 2023: contributor

    Please keep your commits squashed

    Squashed and rebased onto current master.

  16. maflcko commented at 11:17 am on June 28, 2023: member

    I’m guessing we should consider doing the same for zero_after_free_allocator? Even though it doesn’t seem to be affected by this particular issue.

    That’s probably a good idea, yes.

    Looks like this wasn’t addressed yet?

  17. jamesob commented at 4:52 pm on June 28, 2023: member
    Concept ACK. Thanks for filing the change @CaseyCarter, and welcome to the project!
  18. john-moffett commented at 6:15 pm on June 28, 2023: contributor

    Concept ACK and existing code ACK. Thanks for catching this!

    I agree that zero_after_free_allocator also ought to be modified. FWIW, here’s what I did:

     0diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h
     1index 2dc644c242a..35312e9704d 100644
     2--- a/src/support/allocators/zeroafterfree.h
     3+++ b/src/support/allocators/zeroafterfree.h
     4@@ -12,31 +12,46 @@
     5 #include <vector>
     6 
     7 template <typename T>
     8-struct zero_after_free_allocator : public std::allocator<T> {
     9-    using base = std::allocator<T>;
    10-    using traits = std::allocator_traits<base>;
    11-    using size_type = typename traits::size_type;
    12-    using difference_type = typename traits::difference_type;
    13-    using pointer = typename traits::pointer;
    14-    using const_pointer = typename traits::const_pointer;
    15-    using value_type = typename traits::value_type;
    16-    zero_after_free_allocator() noexcept {}
    17-    zero_after_free_allocator(const zero_after_free_allocator& a) noexcept : base(a) {}
    18+struct zero_after_free_allocator {
    19+    using size_type = std::size_t;
    20+    using difference_type = std::ptrdiff_t;
    21+    using pointer = T*;
    22+    using const_pointer = const T*;
    23+    using value_type = T;
    24+
    25+    zero_after_free_allocator() noexcept {};
    26+    zero_after_free_allocator(const zero_after_free_allocator& a) noexcept {};
    27     template <typename U>
    28-    zero_after_free_allocator(const zero_after_free_allocator<U>& a) noexcept : base(a)
    29-    {
    30-    }
    31-    ~zero_after_free_allocator() noexcept {}
    32+    zero_after_free_allocator(const zero_after_free_allocator<U>&) noexcept {};
    33+    ~zero_after_free_allocator() noexcept {};
    34     template <typename Other>
    35     struct rebind {
    36         typedef zero_after_free_allocator<Other> other;
    37     };
    38 
    39+    T* allocate(std::size_t n, const void* hint = nullptr)
    40+    {
    41+        return static_cast<pointer>(::operator new(n * sizeof(T)));
    42+    }
    43+
    44     void deallocate(T* p, std::size_t n)
    45     {
    46-        if (p != nullptr)
    47+        if (p != nullptr) {
    48             memory_cleanse(p, sizeof(T) * n);
    49-        std::allocator<T>::deallocate(p, n);
    50+        }
    51+        ::operator delete(p);
    52+    }
    53+
    54+    template <typename U>
    55+    friend bool operator==(const zero_after_free_allocator&, const zero_after_free_allocator<U>&) noexcept
    56+    {
    57+        return true;
    58+    }
    59+
    60+    template <typename U>
    61+    friend bool operator!=(const zero_after_free_allocator&, const zero_after_free_allocator<U>&) noexcept
    62+    {
    63+        return false;
    64     }
    65 };
    
  19. fanquake commented at 3:30 pm on July 21, 2023: member
    @CaseyCarter did you also want to pickup the change to zero_after_free_allocator ? Otherwise, we can have someone cherry-pick you’re commit into a new PR, and make the additional changes.
  20. fanquake added this to the milestone 26.0 on Jul 21, 2023
  21. CaseyCarter commented at 5:38 pm on July 21, 2023: contributor
    I’ve made consistent changes to zero_after_free_allocator, and also performed some “aggressive cleanup” of cruft in both allocators that’s unnecessary (as far as the Standard Library is concerned) after C++11. The CI will let me know if bitcoin itself was using any of that “cruft”. If I have to fix any fallout, I’ll learn how to build locally and stop lazily relying on CI ;)
  22. jonatack commented at 6:39 pm on July 21, 2023: contributor

    ACK b79d9563169cc990ff2da9a44fef67205e907a8b review and debug built/tested each commit locally

    Note that per https://en.cppreference.com/w/cpp/memory/allocator and related pages, many of the member types and functions are changing with C++20. These can be revisited for updates when this codebase migrates to C++20 or later.

  23. Don't derive secure_allocator from std::allocator
    Affects both secure_allocator and zero_after_free_allocator.
    
    Giving the C++ Standard Committee control of the public interface of your type means they will break it. C++23 adds a new `allocate_at_least` member to `std::allocator`. Very bad things happen when, say, `std::vector` uses `allocate_at_least` from `secure_allocator`'s base to allocate memory which it then tries to free with `secure_allocator::deallocate`.
    
    Drive-by: Aggressively remove facilities unnecessary since C++11 from both allocators to keep things simple.
    07c59eda00
  24. CaseyCarter force-pushed on Jul 25, 2023
  25. CaseyCarter commented at 5:36 am on July 25, 2023: contributor
    Apologies for forgetting to keep the PR squashed. I’ve merged the two commits into one.
  26. DrahtBot added the label CI failed on Jul 25, 2023
  27. fanquake requested review from john-moffett on Jul 25, 2023
  28. fanquake requested review from jamesob on Jul 25, 2023
  29. fanquake requested review from darosior on Jul 25, 2023
  30. DrahtBot removed the label CI failed on Jul 25, 2023
  31. john-moffett approved
  32. john-moffett commented at 6:09 pm on July 25, 2023: contributor
    ACK 07c59eda00841aafaafd8fd648217b56b1e907c9 Reviewed and tested. Performance appears unaffected in my environment.
  33. DrahtBot requested review from jonatack on Jul 25, 2023
  34. jonatack commented at 6:54 pm on July 25, 2023: contributor
    re-ACK 07c59eda00841aafaafd8fd648217b56b1e907c9 no change since my previous ACK apart from squashing the commits
  35. DrahtBot removed review request from jonatack on Jul 25, 2023
  36. achow101 commented at 10:44 pm on July 25, 2023: member
    ACK 07c59eda00841aafaafd8fd648217b56b1e907c9
  37. achow101 merged this on Jul 25, 2023
  38. achow101 closed this on Jul 25, 2023

  39. sidhujag referenced this in commit ea52f3ab8e on Aug 9, 2023
  40. bitcoin locked this on Jul 24, 2024

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: 2024-12-22 00:12 UTC

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