diff options
author | Casey Carter <cacarter@microsoft.com> | 2023-06-21 17:14:53 -0700 |
---|---|---|
committer | Casey Carter <cacarter@microsoft.com> | 2023-07-24 22:33:40 -0700 |
commit | 07c59eda00841aafaafd8fd648217b56b1e907c9 (patch) | |
tree | 20b3614e414238378396a55083a27a52fd6f49b4 /src | |
parent | 6a473373d4953cabbb219eae8b709150a45796e6 (diff) |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/support/allocators/secure.h | 36 | ||||
-rw-r--r-- | src/support/allocators/zeroafterfree.h | 39 |
2 files changed, 39 insertions, 36 deletions
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h index b2076bea07..558f835f11 100644 --- a/src/support/allocators/secure.h +++ b/src/support/allocators/secure.h @@ -17,27 +17,14 @@ // out of memory and clears its contents before deletion. // template <typename T> -struct secure_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; - secure_allocator() noexcept {} - secure_allocator(const secure_allocator& a) noexcept : base(a) {} +struct secure_allocator { + using value_type = T; + + secure_allocator() = default; template <typename U> - secure_allocator(const secure_allocator<U>& a) noexcept : base(a) - { - } - ~secure_allocator() noexcept {} - template <typename Other> - struct rebind { - typedef secure_allocator<Other> other; - }; + secure_allocator(const secure_allocator<U>&) noexcept {} - T* allocate(std::size_t n, const void* hint = nullptr) + T* allocate(std::size_t n) { T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); if (!allocation) { @@ -53,6 +40,17 @@ struct secure_allocator : public std::allocator<T> { } LockedPoolManager::Instance().free(p); } + + template <typename U> + friend bool operator==(const secure_allocator&, const secure_allocator<U>&) noexcept + { + return true; + } + template <typename U> + friend bool operator!=(const secure_allocator&, const secure_allocator<U>&) noexcept + { + return false; + } }; // This is exactly like std::string, but with a custom allocator. diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h index 2dc644c242..6d50eb70a6 100644 --- a/src/support/allocators/zeroafterfree.h +++ b/src/support/allocators/zeroafterfree.h @@ -12,31 +12,36 @@ #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 value_type = T; + + zero_after_free_allocator() noexcept = default; template <typename U> - zero_after_free_allocator(const zero_after_free_allocator<U>& a) noexcept : base(a) + zero_after_free_allocator(const zero_after_free_allocator<U>&) noexcept + { + } + + T* allocate(std::size_t n) { + return std::allocator<T>{}.allocate(n); } - ~zero_after_free_allocator() noexcept {} - template <typename Other> - struct rebind { - typedef zero_after_free_allocator<Other> other; - }; void deallocate(T* p, std::size_t n) { if (p != nullptr) memory_cleanse(p, sizeof(T) * n); - std::allocator<T>::deallocate(p, n); + std::allocator<T>{}.deallocate(p, n); + } + + 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; } }; |