问题
I'm writing some code that handles cryptographic secrets, and I've created a custom ZeroedMemory
implementation of std::pmr::memory_resource
which handles sanitizes memory on deallocation and encapsulates using the magic you have to use to prevent optimizing compilers from eliding away the operation. The idea was to avoid specializing std::array
, because the lack of a virtual destructor means that destruction after type erasure would cause memory to be freed without being sanitized.
Unfortunately, I came to realize afterwards that std::array
isn't an AllocatorAwareContainer
. My std::pmr::polymorphic_allocator
approach was a bit misguided, since obviously there's no room in an std::array
to store a pointer to a specific allocator instance. Still, I can't fathom why allocators for which std::allocator_traits<A>::is_always_equal::value == true
wouldn't be allowed, and I could easily re-implement my solution as a generic Allocator
instead of the easier-to-use std::pmr::memory_resource
...
Now, I could normally just use an std::pmr::vector
instead, but one of the nice features of std::array
is that the length of the array is part of the type. If I'm dealing with a 32-byte key, for example, I don't have to do runtime checks to be sure that the std::array<uint8_t, 32>
parameter someone passed to my function is, in fact, the right length. In fact, those cast down nicely to a const std::span<uint8_t, 32>
, which vastly simplifies writing functions that need to interoperate with C code because they enable me to handle arbitrary memory blocks from any source basically for free.
Ironically, std::tuple
takes allocators... but I shudder to imagine the typedef needed to handle a 32-byte std::tuple<uint8_t, uint8_t, uint8_t, uint8_t, ...>
.
So: is there any standard-ish type that holds a fixed number of homogenously-typed items, a la std::array
, but is allocator aware (and preferably stores the items in a continguous region, so it can be down-cast to an std::span
)?
回答1:
You need cooperation from both the compiler and the OS in order for such a scheme to work. P1315 is a proposal to address the compiler/language side of things. As for the OS, you have to make sure that the memory was never paged out to disk, etc. in order for this to truly zero memory.
回答2:
This sounds like a XY problem. You seem to be misusing allocators. Allocators are used to handle runtime memory allocation and deallocation, not to hook stack memory. What you are trying to do — zeroing the memory after using — should really be done with a destructor. You may want to write a class Key
for this:
class Key {
public:
// ...
~Key()
{
secure_clear(*this); // for illustration
}
// ...
private:
std::array<std::uint8_t, 32> key;
};
You can easily implement iterator and span support. And you don't need to play with allocators.
If you want to reduce boilerplate code and make the new class automatically iterator / span friendly, use inheritance:
class Key :public std::array<std::uint8_t, 32> {
public:
// ...
~Key()
{
secure_clear(*this); // for illustration
}
// ...
};
来源:https://stackoverflow.com/questions/57487566/allocator-aware-stdarray-style-container