#include <security_utilities/alloc.h>
#include <security_utilities/memutils.h>
#include <security_utilities/globalizer.h>
#include <stdlib.h>
#include <errno.h>
using LowLevelMemoryUtilities::alignof;
using LowLevelMemoryUtilities::increment;
using LowLevelMemoryUtilities::alignUp;
extern "C" size_t malloc_size(void *);
bool Allocator::operator == (const Allocator &alloc) const throw()
{
return this == &alloc;
}
Allocator::~Allocator()
{
}
struct DefaultAllocator : public Allocator {
void *malloc(size_t size) throw(std::bad_alloc);
void free(void *addr) throw();
void *realloc(void *addr, size_t size) throw(std::bad_alloc);
};
struct SensitiveAllocator : public DefaultAllocator {
void free(void *addr) throw();
void *realloc(void *addr, size_t size) throw(std::bad_alloc);
};
struct DefaultAllocators {
DefaultAllocator standard;
SensitiveAllocator sensitive;
};
static ModuleNexus<DefaultAllocators> defaultAllocators;
Allocator &Allocator::standard(UInt32 request)
{
switch (request) {
case normal:
return defaultAllocators().standard;
case sensitive:
return defaultAllocators().sensitive;
default:
UnixError::throwMe(ENOMEM);
}
}
void *DefaultAllocator::malloc(size_t size) throw(std::bad_alloc)
{
if (void *result = ::malloc(size))
return result;
throw std::bad_alloc();
}
void DefaultAllocator::free(void *addr) throw()
{
::free(addr);
}
void *DefaultAllocator::realloc(void *addr, size_t newSize) throw(std::bad_alloc)
{
if (void *result = ::realloc(addr, newSize))
return result;
throw std::bad_alloc();
}
void SensitiveAllocator::free(void *addr) throw()
{
memset(addr, 0, malloc_size(addr));
DefaultAllocator::free(addr);
}
void *SensitiveAllocator::realloc(void *addr, size_t newSize) throw(std::bad_alloc)
{
size_t oldSize = malloc_size(addr);
if (newSize < oldSize)
memset(increment(addr, newSize), 0, oldSize - newSize);
return DefaultAllocator::realloc(addr, newSize);
}
void *CssmHeap::operator new (size_t size, Allocator *alloc) throw(std::bad_alloc)
{
if (alloc == NULL)
alloc = &Allocator::standard();
size = alignUp(size, alignof<Allocator *>());
size_t totalSize = size + sizeof(Allocator *);
void *addr = alloc->malloc(totalSize);
*(Allocator **)increment(addr, size) = alloc;
return addr;
}
void CssmHeap::operator delete (void *addr, size_t size, Allocator *alloc) throw()
{
alloc->free(addr); }
void CssmHeap::operator delete (void *addr, size_t size) throw()
{
void *end = increment(addr, alignUp(size, alignof<Allocator *>()));
(*(Allocator **)end)->free(addr);
}