Skip to content

Commit 3b3fdaa

Browse files
achow101vijaydasmp
authored andcommitted
Merge bitcoin#27930: util: Don't derive secure_allocator from std::allocator
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
1 parent 0ad41d1 commit 3b3fdaa

File tree

2 files changed

+39
-36
lines changed

2 files changed

+39
-36
lines changed

src/support/allocators/secure.h

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,14 @@
1818
// out of memory and clears its contents before deletion.
1919
//
2020
template <typename T>
21-
struct secure_allocator : public std::allocator<T> {
22-
using base = std::allocator<T>;
23-
using traits = std::allocator_traits<base>;
24-
using size_type = typename traits::size_type;
25-
using difference_type = typename traits::difference_type;
26-
using pointer = typename traits::pointer;
27-
using const_pointer = typename traits::const_pointer;
28-
using value_type = typename traits::value_type;
29-
secure_allocator() noexcept {}
30-
secure_allocator(const secure_allocator& a) noexcept : base(a) {}
21+
struct secure_allocator {
22+
using value_type = T;
23+
24+
secure_allocator() = default;
3125
template <typename U>
32-
secure_allocator(const secure_allocator<U>& a) noexcept : base(a)
33-
{
34-
}
35-
~secure_allocator() noexcept {}
36-
template <typename _Other>
37-
struct rebind {
38-
typedef secure_allocator<_Other> other;
39-
};
26+
secure_allocator(const secure_allocator<U>&) noexcept {}
4027

41-
T* allocate(std::size_t n, const void* hint = nullptr)
28+
T* allocate(std::size_t n)
4229
{
4330
T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n));
4431
if (!allocation) {
@@ -54,6 +41,17 @@ struct secure_allocator : public std::allocator<T> {
5441
}
5542
LockedPoolManager::Instance().free(p);
5643
}
44+
45+
template <typename U>
46+
friend bool operator==(const secure_allocator&, const secure_allocator<U>&) noexcept
47+
{
48+
return true;
49+
}
50+
template <typename U>
51+
friend bool operator!=(const secure_allocator&, const secure_allocator<U>&) noexcept
52+
{
53+
return false;
54+
}
5755
};
5856

5957
// This is exactly like std::string, but with a custom allocator.

src/support/allocators/zeroafterfree.h

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,36 @@
1212
#include <vector>
1313

1414
template <typename T>
15-
struct zero_after_free_allocator : public std::allocator<T> {
16-
using base = std::allocator<T>;
17-
using traits = std::allocator_traits<base>;
18-
using size_type = typename traits::size_type;
19-
using difference_type = typename traits::difference_type;
20-
using pointer = typename traits::pointer;
21-
using const_pointer = typename traits::const_pointer;
22-
using value_type = typename traits::value_type;
23-
zero_after_free_allocator() noexcept {}
24-
zero_after_free_allocator(const zero_after_free_allocator& a) noexcept : base(a) {}
15+
struct zero_after_free_allocator {
16+
using value_type = T;
17+
18+
zero_after_free_allocator() noexcept = default;
2519
template <typename U>
26-
zero_after_free_allocator(const zero_after_free_allocator<U>& a) noexcept : base(a)
20+
zero_after_free_allocator(const zero_after_free_allocator<U>&) noexcept
21+
{
22+
}
23+
24+
T* allocate(std::size_t n)
2725
{
26+
return std::allocator<T>{}.allocate(n);
2827
}
29-
~zero_after_free_allocator() noexcept {}
30-
template <typename _Other>
31-
struct rebind {
32-
typedef zero_after_free_allocator<_Other> other;
33-
};
3428

3529
void deallocate(T* p, std::size_t n)
3630
{
3731
if (p != nullptr)
3832
memory_cleanse(p, sizeof(T) * n);
39-
std::allocator<T>::deallocate(p, n);
33+
std::allocator<T>{}.deallocate(p, n);
34+
}
35+
36+
template <typename U>
37+
friend bool operator==(const zero_after_free_allocator&, const zero_after_free_allocator<U>&) noexcept
38+
{
39+
return true;
40+
}
41+
template <typename U>
42+
friend bool operator!=(const zero_after_free_allocator&, const zero_after_free_allocator<U>&) noexcept
43+
{
44+
return false;
4045
}
4146
};
4247

0 commit comments

Comments
 (0)