+110
-31
@@ -1,69 +1,148 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "stdlib.h"
|
||||
#include <mutex>
|
||||
#ifdef DEBUG
|
||||
#include "MemDebug.hpp"
|
||||
#include <exception>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
static std::mutex memMutex;
|
||||
|
||||
struct MemStats {
|
||||
size_t allocated = 0;
|
||||
size_t allocations = 0;
|
||||
|
||||
|
||||
static MemStats memStats;
|
||||
|
||||
const MemStats&pipedal::GetMemStats()
|
||||
{
|
||||
return memStats;
|
||||
}
|
||||
|
||||
const size_t MEM_GUARD = (size_t)0xBAADF00DBAADF00D;
|
||||
|
||||
struct MemHeader {
|
||||
size_t size = 0;
|
||||
MemHeader*pNext = nullptr;
|
||||
MemHeader *pPrev = nullptr;
|
||||
size_t mem_guard = MEM_GUARD;
|
||||
|
||||
};
|
||||
|
||||
MemStats memStats;
|
||||
static MemHeader memHead;
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
char *p = (char*)malloc(size+32+4);
|
||||
{
|
||||
std::lock_guard lock(memMutex);
|
||||
MemHeader *pHead = (MemHeader*)p;
|
||||
pHead->size = size;
|
||||
pHead->pNext = nullptr;
|
||||
pHead->pPrev = nullptr;
|
||||
pHead->mem_guard = MEM_GUARD;
|
||||
memStats.allocated += size;
|
||||
memStats.allocations++;
|
||||
}
|
||||
|
||||
char *p = (char*)malloc(size+8);
|
||||
((size_t*)p)[0] = size;
|
||||
return p+8;
|
||||
// link block into allocation chain
|
||||
if (memHead.pNext == nullptr)
|
||||
{
|
||||
memHead.pNext = memHead.pPrev = pHead;
|
||||
pHead->pNext = pHead->pPrev = &memHead;
|
||||
} else {
|
||||
pHead->pNext = memHead.pNext;
|
||||
pHead->pNext->pPrev = pHead;
|
||||
pHead->pPrev = &memHead;
|
||||
memHead.pNext = pHead;
|
||||
}
|
||||
|
||||
p = p+32;
|
||||
char *endGuard = p + size;
|
||||
*endGuard++ = (char)0xBA;
|
||||
*endGuard++ = (char)0xAD;
|
||||
*endGuard++ = (char)0xF0;
|
||||
*endGuard++ = (char)0x0D;
|
||||
|
||||
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void bad_alloc();
|
||||
|
||||
void operator delete(void*mem)
|
||||
{
|
||||
if (mem == nullptr) return;
|
||||
|
||||
char *p = ((char*)mem);
|
||||
size_t size = *(size_t*)(p-8);
|
||||
|
||||
{
|
||||
MemHeader *pHeader = (MemHeader*)(p-32);
|
||||
std::lock_guard lock(memMutex);
|
||||
memStats.allocated -= size;
|
||||
memStats.allocated -= pHeader->size;
|
||||
memStats.allocations--;
|
||||
|
||||
// check the memory guards.
|
||||
if (pHeader->mem_guard != MEM_GUARD)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
char *pTail = p + pHeader->size;
|
||||
if (*pTail++ != (char)0xBA) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
if (*pTail++ != (char)0xAD) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
if (*pTail++ != (char)0xF0) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
if (*pTail++ != (char)0x0D) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
// invalidate the memory guards (double free, eg).
|
||||
pHeader->mem_guard = (size_t)0xDDDDDDDD;
|
||||
pTail = p + pHeader->size;
|
||||
*pTail++ = (char)0xDD;
|
||||
*pTail++ = (char)0xDD;
|
||||
*pTail++ = (char)0xDD;
|
||||
*pTail++ = (char)0xDD;
|
||||
|
||||
// unlink the block from the allocation chain.
|
||||
pHeader->pNext->pPrev = pHeader->pPrev;
|
||||
pHeader->pPrev->pNext = pHeader->pNext;
|
||||
pHeader->pNext = nullptr;
|
||||
pHeader->pPrev = nullptr;
|
||||
|
||||
}
|
||||
free(p-32);
|
||||
|
||||
|
||||
free(p-8);
|
||||
}
|
||||
|
||||
void* operator new[](size_t size)
|
||||
{
|
||||
{
|
||||
std::lock_guard lock(memMutex);
|
||||
memStats.allocated += size;
|
||||
memStats.allocations++;
|
||||
}
|
||||
|
||||
char *p = (char*)malloc(size+8);
|
||||
((size_t*)p)[0] = size;
|
||||
return p+8;
|
||||
return operator new(size);
|
||||
}
|
||||
|
||||
void operator delete[](void*mem)
|
||||
{
|
||||
char *p = ((char*)mem);
|
||||
size_t size = *(size_t*)(p-8);
|
||||
{
|
||||
std::lock_guard lock(memMutex);
|
||||
memStats.allocated -= size;
|
||||
memStats.allocations--;
|
||||
}
|
||||
|
||||
free(p-8);
|
||||
return operator delete(mem);
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user