Improve UnswappableAllocator for Windows. It is now guaranteed to not unlock memory too early because of close allocations next to it
This commit is contained in:
parent
13f820975a
commit
e006a4057f
@ -7,7 +7,12 @@
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
// This allocator allocates memory that won't be swapped out to the disk, but will be kept in RAM
|
||||
/**
|
||||
* Allocator for security relevant memory like key data.
|
||||
* The operating system will be given a hint that this memory shouldn't be swapped out to disk
|
||||
* (which is, however, only a hint and might be ignored),
|
||||
* and we'll make sure the memory is zeroed-out when deallocated.
|
||||
*/
|
||||
class UnswappableAllocator final : public Allocator {
|
||||
public:
|
||||
void* allocate(size_t size) override;
|
||||
|
@ -10,24 +10,39 @@ using namespace cpputils::logging;
|
||||
namespace cpputils {
|
||||
|
||||
void* UnswappableAllocator::allocate(size_t size) {
|
||||
void* data = DefaultAllocator().allocate(size);
|
||||
const BOOL result = ::VirtualLock(data, size);
|
||||
if (!result) {
|
||||
// VirtualAlloc allocates memory in full pages. This is needed, because VirtualUnlock unlocks full pages
|
||||
// and might otherwise unlock unrelated memory of other allocations.
|
||||
|
||||
// allocate pages
|
||||
void* data = ::VirtualAlloc(nullptr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
if (nullptr == data) {
|
||||
throw std::runtime_error("Error calling VirtualAlloc. Errno: " + std::to_string(GetLastError()));
|
||||
}
|
||||
|
||||
// lock allocated pages into RAM
|
||||
const BOOL success = ::VirtualLock(data, size);
|
||||
if (!success) {
|
||||
throw std::runtime_error("Error calling VirtualLock. Errno: " + std::to_string(GetLastError()));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void UnswappableAllocator::free(void* data, size_t size) {
|
||||
const BOOL result = ::VirtualUnlock(data, size);
|
||||
if (!result) {
|
||||
LOG(WARN, "Error calling VirtualUnlock. Errno: {}", GetLastError());
|
||||
}
|
||||
|
||||
// overwrite the memory with zeroes before we free it
|
||||
std::memset(data, 0, size);
|
||||
|
||||
DefaultAllocator().free(data, size);
|
||||
// unlock allocated pages from RAM
|
||||
BOOL success = ::VirtualUnlock(data, size);
|
||||
if (!success) {
|
||||
throw std::runtime_error("Error calling VirtualUnlock. Errno: " + std::to_string(GetLastError()));
|
||||
}
|
||||
|
||||
// free allocated pages
|
||||
success = ::VirtualFree(data, 0, MEM_RELEASE);
|
||||
if (!success) {
|
||||
throw std::runtime_error("Error calling VirtualFree. Errno: " + std::to_string(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user