Pointer tracking

This commit is contained in:
Iliyas Jorio 2021-07-30 00:07:37 +02:00
parent 77fda7913d
commit 6f5592fbc3
3 changed files with 123 additions and 32 deletions

View File

@ -1,5 +1,4 @@
#include <iostream> #include <iostream>
#include <vector>
#include <cstring> #include <cstring>
#include "Pomme.h" #include "Pomme.h"
@ -10,30 +9,81 @@ using namespace Pomme::Memory;
#define LOG POMME_GENLOG(POMME_DEBUG_MEMORY, "MEMO") #define LOG POMME_GENLOG(POMME_DEBUG_MEMORY, "MEMO")
#if POMME_PTR_TRACKING
#include <set>
static uint32_t gCurrentPtrBatch = 0;
static uint32_t gCurrentNumPtrsInBatch = 0;
static std::set<uint32_t> gLivePtrNums;
#endif
static constexpr int kBlockDescriptorPadding = 32;
static_assert(sizeof(BlockDescriptor) <= kBlockDescriptorPadding);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Implementation-specific stuff // Implementation-specific stuff
BlockDescriptor::BlockDescriptor(Size theSize) BlockDescriptor* BlockDescriptor::Allocate(uint32_t size)
{ {
buf = new char[theSize]; char* buf = new char[kBlockDescriptorPadding + size];
magic = 'LIVE';
size = theSize; BlockDescriptor* block = (BlockDescriptor*) buf;
block->magic = 'LIVE';
block->size = size;
block->ptrToData = buf + kBlockDescriptorPadding;
block->rezMeta = nullptr;
#if POMME_PTR_TRACKING
block->ptrBatch = gCurrentPtrBatch;
block->ptrNumInBatch = gCurrentNumPtrsInBatch++;
gLivePtrNums.insert(block->ptrNumInBatch);
#endif
return block;
} }
BlockDescriptor::~BlockDescriptor() void BlockDescriptor::Free(BlockDescriptor* block)
{ {
if (!block)
return;
block->magic = 'DEAD';
block->size = 0;
block->ptrToData = nullptr;
block->rezMeta = nullptr;
#if POMME_PTR_TRACKING
if (block->ptrBatch == gCurrentPtrBatch)
gLivePtrNums.erase(block->ptrNumInBatch);
#endif
char* buf = (char*) block;
delete[] buf; delete[] buf;
buf = nullptr; }
size = 0;
rezMeta = nullptr; void BlockDescriptor::CheckIsLive() const
magic = 'DEAD'; {
if (magic == 'DEAD')
throw std::runtime_error("ptr/handle double free?");
if (magic != 'LIVE')
throw std::runtime_error("corrupted ptr/handle");
} }
BlockDescriptor* BlockDescriptor::HandleToBlock(Handle h) BlockDescriptor* BlockDescriptor::HandleToBlock(Handle h)
{ {
auto bd = (BlockDescriptor*) h; if (!h || !*h)
if (bd->magic != 'LIVE') return nullptr;
throw std::runtime_error("corrupted handle"); BlockDescriptor* bd = (BlockDescriptor*) (*h - kBlockDescriptorPadding);
bd->CheckIsLive();
return bd;
}
BlockDescriptor* BlockDescriptor::PtrToBlock(Ptr p)
{
if (!p)
return nullptr;
BlockDescriptor* bd = (BlockDescriptor*) (p - kBlockDescriptorPadding);
bd->CheckIsLive();
return bd; return bd;
} }
@ -44,13 +94,11 @@ Handle NewHandle(Size size)
{ {
if (size < 0) if (size < 0)
throw std::invalid_argument("trying to alloc negative size handle"); throw std::invalid_argument("trying to alloc negative size handle");
if (size > 0x7FFFFFFF)
throw std::invalid_argument("trying to alloc massive handle");
BlockDescriptor* block = new BlockDescriptor(size); BlockDescriptor* block = BlockDescriptor::Allocate(size);
return &block->ptrToData;
if ((Ptr) &block->buf != (Ptr) block)
throw std::runtime_error("buffer address mismatches block address");
return &block->buf;
} }
Handle NewHandleClear(Size s) Handle NewHandleClear(Size s)
@ -89,7 +137,7 @@ void SetHandleSize(Handle handle, Size byteCount)
void DisposeHandle(Handle h) void DisposeHandle(Handle h)
{ {
delete BlockDescriptor::HandleToBlock(h); BlockDescriptor::Free(BlockDescriptor::HandleToBlock(h));
} }
OSErr PtrToHand(const void* srcPtr, Handle* dstHndl, Size size) OSErr PtrToHand(const void* srcPtr, Handle* dstHndl, Size size)
@ -117,27 +165,56 @@ OSErr PtrToHand(const void* srcPtr, Handle* dstHndl, Size size)
Ptr NewPtr(Size byteCount) Ptr NewPtr(Size byteCount)
{ {
if (byteCount < 0) throw std::invalid_argument("trying to NewPtr negative size"); if (byteCount < 0)
throw std::invalid_argument("trying to NewPtr negative size");
if (byteCount > 0x7FFFFFFF)
throw std::invalid_argument("trying to alloc massive ptr");
#if !POMME_PTR_TRACKING
return new char[byteCount]; return new char[byteCount];
#else
BlockDescriptor* bd = BlockDescriptor::Allocate(byteCount);
return bd->ptrToData;
#endif
} }
Ptr NewPtrSys(Size byteCount) Ptr NewPtrSys(Size byteCount)
{ {
if (byteCount < 0) throw std::invalid_argument("trying to NewPtrSys negative size"); return NewPtr(byteCount);
return new char[byteCount];
} }
Ptr NewPtrClear(Size byteCount) Ptr NewPtrClear(Size byteCount)
{ {
if (byteCount < 0) throw std::invalid_argument("trying to NewPtrClear negative size"); Ptr ptr = NewPtr(byteCount);
Ptr ptr = new char[byteCount];
memset(ptr, 0, byteCount); memset(ptr, 0, byteCount);
return ptr; return ptr;
} }
void DisposePtr(Ptr p) void DisposePtr(Ptr p)
{ {
#if !POMME_PTR_TRACKING
delete[] p; delete[] p;
#else
BlockDescriptor::Free(BlockDescriptor::PtrToBlock(p));
#endif
}
//-----------------------------------------------------------------------------
// Memory: pointer tracking
void Pomme_FlushPtrTracking(bool issueWarnings)
{
#if POMME_PTR_TRACKING
if (issueWarnings && !gLivePtrNums.empty())
{
for (uint32_t ptrNum : gLivePtrNums)
printf("%s: ptr/handle %d:%d is still live!\n", __func__, gCurrentPtrBatch, ptrNum);
}
gLivePtrNums.clear();
gCurrentPtrBatch++;
gCurrentNumPtrsInBatch = 0;
#endif
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -419,6 +419,11 @@ Ptr NewPtrClear(Size);
void DisposePtr(Ptr p); void DisposePtr(Ptr p);
//-----------------------------------------------------------------------------
// Memory: pointer tracking
void Pomme_FlushPtrTracking(bool issueWarnings);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Memory: BlockMove // Memory: BlockMove

View File

@ -1,5 +1,9 @@
#pragma once #pragma once
#if !defined(POMME_PTR_TRACKING)
#define POMME_PTR_TRACKING _DEBUG
#endif
namespace Pomme::Files namespace Pomme::Files
{ {
struct ResourceMetadata; struct ResourceMetadata;
@ -7,19 +11,24 @@ namespace Pomme::Files
namespace Pomme::Memory namespace Pomme::Memory
{ {
class BlockDescriptor struct BlockDescriptor
{ {
public: uint32_t magic;
Ptr buf; uint32_t size;
OSType magic; uint32_t ptrBatch;
Size size; uint32_t ptrNumInBatch;
Ptr ptrToData;
const Pomme::Files::ResourceMetadata* rezMeta; const Pomme::Files::ResourceMetadata* rezMeta;
BlockDescriptor(Size theSize); static BlockDescriptor* Allocate(uint32_t size);
~BlockDescriptor(); static void Free(BlockDescriptor* block);
void CheckIsLive() const;
static BlockDescriptor* HandleToBlock(Handle h); static BlockDescriptor* HandleToBlock(Handle h);
static BlockDescriptor* PtrToBlock(Ptr p);
}; };
class DisposeHandleGuard class DisposeHandleGuard