Files
op-pedal/src/MemDebug.cpp
T
Robin Davies 2b2e82730c Automated Build Tests
Fixes #34
2022-03-16 00:18:17 -04:00

149 lines
3.9 KiB
C++

// 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>
#include "MemDebug.hpp"
#include <exception>
using namespace pipedal;
static std::mutex memMutex;
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;
};
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++;
// 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);
{
MemHeader *pHeader = (MemHeader*)(p-32);
std::lock_guard lock(memMutex);
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);
}
void* operator new[](size_t size)
{
return operator new(size);
}
void operator delete[](void*mem)
{
return operator delete(mem);
}