-
Notifications
You must be signed in to change notification settings - Fork 37.7k
util: Don't derive secure_allocator from std::allocator #27930
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. |
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 From microsoft/STL#3819:
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? |
That's probably a good idea, yes.
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 |
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) |
Squashed and rebased onto current |
Looks like this wasn't addressed yet? |
Concept ACK. Thanks for filing the change @CaseyCarter, and welcome to the project! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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:
diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h
index 2dc644c242a..35312e9704d 100644
--- a/src/support/allocators/zeroafterfree.h
+++ b/src/support/allocators/zeroafterfree.h
@@ -12,31 +12,46 @@
#include <vector>
template <typename T>
-struct zero_after_free_allocator : public std::allocator<T> {
- using base = std::allocator<T>;
- using traits = std::allocator_traits<base>;
- using size_type = typename traits::size_type;
- using difference_type = typename traits::difference_type;
- using pointer = typename traits::pointer;
- using const_pointer = typename traits::const_pointer;
- using value_type = typename traits::value_type;
- zero_after_free_allocator() noexcept {}
- zero_after_free_allocator(const zero_after_free_allocator& a) noexcept : base(a) {}
+struct zero_after_free_allocator {
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using value_type = T;
+
+ zero_after_free_allocator() noexcept {};
+ zero_after_free_allocator(const zero_after_free_allocator& a) noexcept {};
template <typename U>
- zero_after_free_allocator(const zero_after_free_allocator<U>& a) noexcept : base(a)
- {
- }
- ~zero_after_free_allocator() noexcept {}
+ zero_after_free_allocator(const zero_after_free_allocator<U>&) noexcept {};
+ ~zero_after_free_allocator() noexcept {};
template <typename Other>
struct rebind {
typedef zero_after_free_allocator<Other> other;
};
+ T* allocate(std::size_t n, const void* hint = nullptr)
+ {
+ return static_cast<pointer>(::operator new(n * sizeof(T)));
+ }
+
void deallocate(T* p, std::size_t n)
{
- if (p != nullptr)
+ if (p != nullptr) {
memory_cleanse(p, sizeof(T) * n);
- std::allocator<T>::deallocate(p, n);
+ }
+ ::operator delete(p);
+ }
+
+ template <typename U>
+ friend bool operator==(const zero_after_free_allocator&, const zero_after_free_allocator<U>&) noexcept
+ {
+ return true;
+ }
+
+ template <typename U>
+ friend bool operator!=(const zero_after_free_allocator&, const zero_after_free_allocator<U>&) noexcept
+ {
+ return false;
}
};
@CaseyCarter did you also want to pickup the change to |
I've made consistent changes to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK b79d956 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.
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.
Apologies for forgetting to keep the PR squashed. I've merged the two commits into one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 07c59ed Reviewed and tested. Performance appears unaffected in my environment.
re-ACK 07c59ed no change since my previous ACK apart from squashing the commits |
ACK 07c59ed |
…locator 07c59ed Don't derive secure_allocator from std::allocator (Casey Carter) Pull request description: 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.) ACKs for top commit: jonatack: re-ACK 07c59ed no change since my previous ACK apart from squashing the commits achow101: ACK 07c59ed john-moffett: ACK 07c59ed Reviewed and tested. Performance appears unaffected in my environment. Tree-SHA512: 23606c40414d325f5605a9244d4dd50907fdf5f2fbf70f336accb3a2cb98baa8acd2972f46eab1b7fdec1d28a843a96b06083cd2d09791cda7c90ee218e5bbd5
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 tostd::allocator
. Very bad things happen when, say,std::vector
usesallocate_at_least
fromsecure_allocator
's base to allocate memory which it then tries to free withsecure_allocator::deallocate
.(Discovered by microsoft/STL#3712, which will be reverted by microsoft/STL#3819 before it ships.)