1
#include "../NKernel.h"
2
#include "../Math/MathUtility.h"
3
#include "../DataStruct/NList.h"
4
#include "NMemoryDebugHook.h"
7
#ifdef GEAR_CFG_USE_MEMPAGEHOOK_STUB
8
#include GEAR_INCLUDE_MEMPAGEHOOK_STUB
10
// When the mempagehook is used, lets use the its functions
11
#define __GEAR_GET_ID(pData) GEAR_MEM_PAGE_HOOK_FIND_ALLOCATOR(pData).GetId()
12
#define __GEAR_VALIDATE(pData) GEAR_MEM_PAGE_HOOK_VALIDATE(pData)
14
// When the mempagehook is not used, lets use the the default behavior
15
#define __GEAR_GET_ID(pData) NMemoryAllocatorInterface::VOID_ALLOC_ID
16
#define __GEAR_VALIDATE(pData) true
22
//NOTE on Optimization : It is REALY important that these 2 functions do not get optimized.
23
// Since they have no end result, they will be emptied by the compiler if optimization is on.
24
#pragma optimize("", off)
25
bool IsBadReadPointer(void* ptr, t_u32 memSize)
28
t_u8* ptr8 = (t_u8*)ptr;
34
for(t_u32 i=0; i < memSize; i++)
39
__except (EXCEPTION_EXECUTE_HANDLER)
46
bool IsBadWritePointer(void* ptr, t_u32 memSize)
49
t_u8* ptr8 = (t_u8*)ptr;
55
for(t_u32 i=0; i < memSize; i++)
63
__except (EXCEPTION_EXECUTE_HANDLER)
70
#pragma optimize("", on)
73
///Returns the amount of bytes equal to value in the current buffer
74
t_uaddress GetBufferPatternLength(const t_u8 *startOfBuffer, t_u8 value, t_u32 bufferSize)
76
const t_u8* endOfBuffer = startOfBuffer + bufferSize;
77
const t_u8* rounded = (const t_u8*) INL_ADDRESS_TO_PTR(RoundUp(INL_PTR_TO_ADDRESS(startOfBuffer), sizeof(t_word)));
78
const t_u8* pIndex = startOfBuffer;
80
//we do the first bytes up until alignment
81
while(pIndex < rounded && pIndex < endOfBuffer && (*pIndex == value))
86
if(*pIndex == value && pIndex < endOfBuffer) //we go till the end!
88
//we check word by word which is between 1.2 and 2 times faster than byte per byte
89
t_word fullFillValue = value << 24 | value << 16 | value << 8 | value;
91
rounded = (const t_u8*) INL_ADDRESS_TO_PTR(RoundDown(INL_PTR_TO_ADDRESS(endOfBuffer), sizeof(t_word)));
93
while((*(t_word*)pIndex) == fullFillValue && pIndex < rounded)
94
pIndex+= sizeof(t_word);
97
while(*pIndex == value && (char*)pIndex < (char*)endOfBuffer)
101
return static_cast<t_uaddress>(DiffPointer((void*)pIndex, (void*)startOfBuffer));
104
///Returns the amount of bytes equal to value in the current buffer, starting from the end of the buffer
105
t_uaddress GetBufferPatternLengthReverse(const t_u8 *startOfBuffer, t_u8 value, t_u32 bufferSize)
107
const t_u8* endOfBuffer = startOfBuffer + bufferSize;
108
const t_u8* rounded = (const t_u8*) INL_ADDRESS_TO_PTR(RoundDown(INL_PTR_TO_ADDRESS(endOfBuffer), sizeof(t_word)));
109
const t_u8 *pIndex = endOfBuffer - 1;
111
//We perform the first check on unaligned bytes
112
while(pIndex >= rounded && *pIndex == value && pIndex >= startOfBuffer)
117
if(*pIndex == value && pIndex >= startOfBuffer)
119
//we check word by word which is between 1.2 and 2 times faster than byte per byte
120
t_word fullFillValue = value << 24 | value << 16 | value << 8 | value;
122
pIndex = rounded - sizeof(t_word);
123
rounded = (const t_u8*) INL_ADDRESS_TO_PTR(RoundUp(INL_PTR_TO_ADDRESS(startOfBuffer), sizeof(t_word)));
125
while((*(t_word*)pIndex) == fullFillValue && pIndex >= rounded)
126
pIndex-= sizeof(t_word);
128
//we do the last part
129
pIndex += sizeof(t_word)-1;
130
while(*pIndex == value && pIndex >= startOfBuffer)
134
return static_cast<t_uaddress>(DiffPointer((void*)endOfBuffer, (void*)pIndex)-1);
137
INL_IMPLEMENT_GLOBAL_OBJECT(MemDebug)
139
// hold values for debugging specific allocation number or address
140
static t_u32 BreakOnAllocationNumber = 0;
141
// hold values for debugging specific allocation number or address
142
static t_uaddress BreakOnAllocationAdress = 0;
144
#define INL_DEFAULT_MEM_ALIGN 16
147
#define FILL_VALUE 0xFA // Value used to fill the memory on alloc
148
#define FULL_FILL_VALUE 0xFAFAFAFA // 32bit value used to fill the memory on alloc
149
#define WIPE_VALUE 0xFE // Value used to crush the memory after free
150
#define STATUS_ALLOC 0x01 // Value to identify a bloc allocated
151
#define STATUS_FREE 0x00 // Value to identify a freed block
153
#define DBG_HDR_SIZE (t_u32)RoundUp(sizeof(dbg_header), INL_DEFAULT_MEM_ALIGN)
154
#define DBG_TRAILER_SIZE sizeof(BOTTOM_FLAG)
155
#define DBG_OVERHEAD_SIZE (DBG_HDR_SIZE + DBG_TRAILER_SIZE)
157
//Status management functions
158
// the first bit is for the status,
159
// the 2-3 bits are for alloc type
160
//the last 5 bits are for the alignment
161
#define SET_STATUS(pHdr, status) pHdr->Status = ((pHdr->Status & 0xfe) | (status & 0x01))
162
#define GET_STATUS(pHdr) (pHdr->Status & 0x01)
164
#define SET_ALLOCATION_TYPE(pHdr, allocType) pHdr->Status = ((pHdr->Status & 0xF9) | ((((t_u8)allocType) & 0x03) << 1))
165
#define GET_ALLOCATION_TYPE(pHdr) ((pHdr->Status & 0x06)>> 1)
167
#define SET_ALIGNMENT(pHdr, Alignment) pHdr->Status = ((pHdr->Status & 0x07) | ((((t_u8)GetLowerPowerOfTwoExponent(Alignment)) & 0x1F) << 3))
168
#define GET_ALIGNMENT(pHdr) (1 << ((pHdr->Status & 0xf8) >> 3))
170
#define COMPUTE_CHECKSUM(pHdr) (pHdr->FrontFlag + pHdr->Size + pHdr->LineNo + pHdr->Status + pHdr->AllocId)
171
// Delimiter in the front of the buffer
172
static const t_u32 FRONT_FLAG = 0xB123456B;
173
// Delimiter at the end of the buffer
174
static const t_u32 BOTTOM_FLAG = 0xE123456E;
176
void MemDebug::Constructor(void)
178
m_SequenceNoServer = 0; // Sequence start with 0
179
m_LeakThresholdSeqNo = 0; // By default threshold = 0
182
for(unsigned i = 0; i < INL_NB_ALLOCATOR_MAX; i++)
184
m_AllocatorTbl[i].FailureDelay = 0;
185
m_AllocatorTbl[i].FailureCount = 0;
190
m_pNextHook = INL_GLOBAL_OBJECT_INSTANCE(MemHook).Hook(this);
192
OnAllocCallback = NULL;
193
OnFreeCallback = NULL;
196
void MemDebug::Destructor(void)
203
INL_GLOBAL_OBJECT_INSTANCE(MemHook).UnHook(this, m_pNextHook);
208
void MemDebug::AllocatorDestruction(NMemoryAllocatorInterface& Allocator)
210
NMemoryAllocatorInterface::id AllocId = Allocator.GetId();
211
nuxAssert(AllocId < INL_NB_ALLOCATOR_MAX);
214
m_AllocatorTbl[AllocId].AllocatedList.Clear();
216
MemoryHook::AllocatorDestruction(Allocator);
219
void* MemDebug::Alloc
223
NMemoryAllocatorInterface& Allocator,
226
const char* pObjType,
228
const TCHAR* pFileName
231
//we need to, at least, satisfy the allocator alignment
232
return AllocAligned(OpId, Size, INL_DEFAULT_MEM_ALIGN, Allocator, pParent, pId, pObjType, LineNo, pFileName);
235
void* MemDebug::AllocAligned
240
NMemoryAllocatorInterface& Allocator,
243
const char* pObjType,
245
const TCHAR* pFileName
250
// Break on specific allocation number.
251
// To set this value, you can either put a breakpoint in MemDebug::Constructor and set it in memory
252
// OR set it in the code and recompile.
253
if (BreakOnAllocationNumber && (BreakOnAllocationNumber == m_SequenceNoServer))
258
if(!VerifyAllocFailure(Allocator.GetId()))
260
if(Alignment <= INL_DEFAULT_MEM_ALIGN)
262
pData = MemoryHook::Alloc( OpId,
263
CalculateDebugSize(Size, Alignment),
272
pData = MemoryHook::AllocAligned( OpId,
273
CalculateDebugSize(Size, Alignment),
284
pData = SecondStageAlloc( pData,
287
Alignment, //Alignment
291
m_SequenceNoServer++);
295
// Break on specific allocation address.
296
// To set this value, you can either put a breakpoint in MemDebug::Constructor and set it in memory
297
// OR set it in the code and recompile.
298
if (BreakOnAllocationAdress && (BreakOnAllocationAdress == t_uaddress(pData)))
303
if (OnAllocCallback != NULL)
305
(*OnAllocCallback)(pData, Size);
310
void* MemDebug::Realloc
314
NMemoryAllocatorInterface& Allocator,
316
const TCHAR* pFileName
319
//we need to, at least, satisfies the allocator alignment
320
return ReallocAligned(pOldPtr, Size, INL_DEFAULT_MEM_ALIGN, Allocator, LineNo, pFileName);
323
void* MemDebug::ReallocAligned
328
NMemoryAllocatorInterface& Allocator,
330
const TCHAR* pFileName
339
Ret = VerifyBlock(pOldPtr, Allocator.GetId());
342
// If the current block is valid...
347
dbg_header* pHeader = NULL;
351
pHeader = SubstractPointer<dbg_header*>(pOldPtr, DBG_HDR_SIZE);
353
// Allocate a new block...
354
// Break on specific allocation number.
355
// To set this value, you can either put a breakpoint in MemDebug::Constructor and set it in memory
356
// OR set it in the code and recompile.
357
if (BreakOnAllocationNumber && (BreakOnAllocationNumber == pHeader->SequenceNo))
365
if(!VerifyAllocFailure(Allocator.GetId()))
367
if(Alignment <= (unsigned)(1 << GetLowerPowerOfTwoExponent(INL_DEFAULT_MEM_ALIGN)))
369
pResult = MemoryHook::Alloc(INL_MEMOP_ALLOC,
370
CalculateDebugSize(Size,Alignment),
379
pResult = MemoryHook::AllocAligned(INL_MEMOP_ALLOC,
380
CalculateDebugSize(Size,Alignment),
393
pResult = SecondStageAlloc(pResult,
400
#if GEAR_CFG_MEM_DEBUG_ALLOCNUMBER_INCREMENT_ON_REALLOC == GEAR_ENABLE
401
m_SequenceNoServer++);
403
pHeader->SequenceNo);
409
// Break on specific allocation address.
410
// To set this value, you can either put a breakpoint in MemDebug::Constructor and set it in memory
411
// OR set it in the code and recompile.
412
if (BreakOnAllocationAdress && (BreakOnAllocationAdress == t_uaddress(pResult)))
422
Memcpy(pResult, pOldPtr, Min(Size, (unsigned) pHeader->Size));
426
Free(INL_MEMOP_FREE, pOldPtr, Allocator, LineNo, pFileName);
434
// VerifyAllocFailure
435
// Returns true when we must simulate an allocation failure
437
bool MemDebug::VerifyAllocFailure
439
NMemoryAllocatorInterface::id AllocId
442
nuxAssert(AllocId < INL_NB_ALLOCATOR_MAX);
444
NScopeLock Scope(&m_Lock);
445
if(m_AllocatorTbl[AllocId].FailureDelay > 0)
447
// Decrease the delay before verifying if failure occur
448
m_AllocatorTbl[AllocId].FailureDelay--;
452
// Delay expired, How many fail must be done?
453
if(m_AllocatorTbl[AllocId].FailureCount > 0)
455
m_AllocatorTbl[AllocId].FailureCount--;
463
t_u32 MemDebug::CalculateDebugSize(t_u32 Size, t_u32 Alignment) const
465
return Size + RoundUp(DBG_HDR_SIZE, Alignment) + DBG_TRAILER_SIZE;
468
void* MemDebug::SecondStageAlloc(
473
NMemoryAllocatorInterface::id AllocId,
475
const TCHAR* pFileName,
479
nuxAssert(IsAligned((t_uaddress)pData, 4));
482
dbg_header* pHeader = (dbg_header*) pData;
484
if(DBG_HDR_SIZE != RoundUp(DBG_HDR_SIZE, Alignment)) //we need to offset everything
486
void* offsetData = AddPointer<void*>(pData, RoundUp(DBG_HDR_SIZE, Alignment));
487
pHeader = SubstractPointer<dbg_header*>(offsetData, DBG_HDR_SIZE);
490
/* Initialize the header */
491
pHeader->m_Node.Clear();
492
pHeader->FrontFlag = FRONT_FLAG; // Front Flag to identify where block starts
493
pHeader->Size = Size; // Block user size
494
pHeader->LineNo = (t_u16) LineNo; // Line where it was allocated
496
SET_STATUS(pHeader, STATUS_ALLOC); // Alloc or freed?
497
SET_ALLOCATION_TYPE(pHeader, optId); // Alloc, new or new[]
498
SET_ALIGNMENT(pHeader, Alignment); //Alignment, 0 means we don't care
500
pHeader->AllocId = AllocId; // Allocator Identifier
501
pHeader->pFileName = pFileName; // Name of File where block has been allocated
502
pHeader->SequenceNo = sequenceNo; // Get a sequential alloc number
504
// Compute the checksum on header
505
pHeader->Checksum = COMPUTE_CHECKSUM(pHeader);
507
// Fill buffer with traceable value...
508
Memset(AddPointer<void*>(pHeader, DBG_HDR_SIZE),
512
/* Set bottom flag */
513
Memcpy(AddPointer<void*>(pHeader, DBG_HDR_SIZE + Size),
517
// Enter the critical section to ad this buffer at the end of the
518
// double linked-list of allocated blocks.
521
m_AllocatorTbl[AllocId].AllocatedList.PushBack(*pHeader);
525
/* Move right after the current header (to user zone) */
526
return(AddPointer<void*>(pHeader, DBG_HDR_SIZE));
534
NMemoryAllocatorInterface& Allocator,
536
const TCHAR* pFileName
539
if(pData && VerifyBlock(pData, Allocator.GetId()) == 0)
541
NScopeLock Scope(&m_Lock);
542
FreeBlock(OpId, pData, Allocator, LineNo, pFileName);
546
t_u32 MemDebug::GetAllocatedSize
549
NMemoryAllocatorInterface& Allocator,
550
t_u32* pRetHeaderSize
557
dbg_header* pHeader = SubstractPointer<dbg_header*>(pData, DBG_HDR_SIZE);
559
void * ptr = (void*)pHeader;
560
t_u32 alignment = GET_ALIGNMENT(pHeader);
562
if(alignment > DBG_HDR_SIZE)
564
ptr = SubstractPointer<void*>(pData, alignment);
567
Result = MemoryHook::GetAllocatedSize(ptr, Allocator, pRetHeaderSize);
572
*pRetHeaderSize += Max(DBG_HDR_SIZE, alignment);
579
unsigned MemDebug::GetDebugOverHead(unsigned alignment) const
581
return CalculateDebugSize(0, alignment) + MemoryHook::GetDebugOverHead(alignment);
585
void MemDebug::FreeBlock
589
NMemoryAllocatorInterface& Allocator,
591
const TCHAR* pFileName
596
dbg_header* pHeader = SubstractPointer<dbg_header*>(pData, DBG_HDR_SIZE);
598
if(GET_STATUS(pHeader) == STATUS_ALLOC)
600
if (OnFreeCallback != NULL)
602
(*OnFreeCallback)(pData, pHeader->Size);
605
m_AllocatorTbl[Allocator.GetId()].AllocatedList.Remove(*pHeader);
607
//Check if the Block was deleted with the correct operator
609
if(GET_ALLOCATION_TYPE(pHeader) != OpId - (INL_MEMOP_FREE - INL_MEMOP_ALLOC))
611
nuxDebugMsg(TEXT("%s(%u): Error detected on Buffer #%u [0x%08lx]. allocated with %s, but released with %s\n%s(%u): Released with %s\n"),
612
IsBadReadPointer((void*)pHeader->pFileName, sizeof(pHeader->pFileName)) ? TEXT("<Bad Pointer>") : ANSI_TO_TCHAR(pHeader->pFileName),
616
((GET_ALLOCATION_TYPE(pHeader) == INL_MEMOP_ALLOC) ? TEXT("Alloc") : ((GET_ALLOCATION_TYPE(pHeader) == INL_MEMOP_NEW)? TEXT("New") : TEXT("New[]"))),
617
((OpId == INL_MEMOP_FREE) ? TEXT("Free") : ((OpId == INL_MEMOP_DELETE) ? TEXT("Delete") : TEXT("Delete[]"))),
620
((OpId == INL_MEMOP_FREE) ? TEXT("Free") : ((OpId == INL_MEMOP_DELETE) ? TEXT("Delete") : TEXT("Delete[]")))
626
SET_STATUS(pHeader, STATUS_FREE);
627
pHeader->pFileName = pFileName;
628
pHeader->LineNo = (t_u16) LineNo;
630
/* Recompute the checksum on header */
631
pHeader->Checksum = COMPUTE_CHECKSUM(pHeader);
633
Memset(pData, WIPE_VALUE, pHeader->Size);
635
//we get the "real" pointer we allocated
636
pData = SubstractPointer<void*>(pData, RoundUp(DBG_HDR_SIZE, GET_ALIGNMENT(pHeader)));
638
MemoryHook::Free(OpId, pData, Allocator, LineNo, pFileName);
643
NFileName filename = pFileName;
644
nuxDebugMsg(TEXT("Buffer freed 2 times (0x%08lx), %s, LINE %u\n"), (size_t) pData, filename.GetCleanFilename().GetTCharPtr(), LineNo);
649
// When freeing a marker, we must also free all the block linked after
650
void MemDebug::FreeMarker(
652
MemStackInterface& StackAllocator,
654
const TCHAR* pFileName
659
NListNoDyn<dbg_header>* pRoot = &m_AllocatorTbl[StackAllocator.GetId()].AllocatedList;
661
NScopeLock Scope(&m_Lock);
662
while(pRoot->Back() >= pMarker)
664
void* pData = AddPointer<void*>(pRoot->Back(), DBG_HDR_SIZE);
665
int Ret = VerifyBlock(pData, StackAllocator);
669
FreeBlock(GET_ALLOCATION_TYPE(pRoot->Back()) + (INL_MEMOP_FREE - INL_MEMOP_ALLOC) , pData, StackAllocator, LineNo, pFileName);
673
// Free the real memory
674
MemoryHook::FreeMarker(pMarker, StackAllocator, LineNo, pFileName);
677
void MemDebug::SetAllocFailure
679
const NMemoryAllocatorInterface& Allocator,
684
NMemoryAllocatorInterface::id Id = Allocator.GetId();
685
nuxAssert(Id < INL_NB_ALLOCATOR_MAX);
687
NScopeLock Scope(&m_Lock);
689
m_AllocatorTbl[Id].FailureDelay = Delay;
690
m_AllocatorTbl[Id].FailureCount = NbFailure;
693
unsigned MemDebug::VerifyLeak(NMemoryAllocatorInterface::id AllocId, bool Verbose)
699
nuxAssert(AllocId < INL_NB_ALLOCATOR_MAX);
701
NScopeLock Scope(&m_Lock);
703
NListNoDyn<dbg_header>::DIterator Iterator(m_AllocatorTbl[AllocId].AllocatedList);
705
while(!Iterator.Empty())
707
pHeader = (dbg_header*) Iterator.Current();
708
pMemFault = AddPointer<void*>(pHeader, DBG_HDR_SIZE);
710
if(pHeader->SequenceNo >= m_LeakThresholdSeqNo)
714
nuxDebugMsg(TEXT("%s(%u): Memory leak detected of %d bytes at address 0x%08x. No. %d\n"),
715
IsBadReadPointer((void*)pHeader->pFileName, sizeof(pHeader->pFileName)) ? TEXT("<Bad Pointer>") : pHeader->pFileName,
719
pHeader->SequenceNo);
731
unsigned MemDebug::VerifyLeakAll(bool Verbose)
735
for(unsigned i = 0; i < INL_NB_ALLOCATOR_MAX; i++)
737
Result += VerifyLeak((NMemoryAllocatorInterface::id) i, Verbose);
744
int MemDebug::VerifyBuffer(NMemoryAllocatorInterface::id AllocId, bool Verbose)
749
nuxAssert(AllocId < INL_NB_ALLOCATOR_MAX);
751
NScopeLock Scope(&m_Lock);
753
NListNoDyn<dbg_header>::DIterator Iterator(m_AllocatorTbl[AllocId].AllocatedList);
755
while((!Iterator.Empty()) && (Result == 0))
757
pBuf = AddPointer<void*>(Iterator.Current(), DBG_HDR_SIZE);
758
Result = VerifyBlock(pBuf, AllocId, Verbose);
765
unsigned MemDebug::VerifyBufferAll(bool Verbose)
769
for(unsigned i = 0; i < INL_NB_ALLOCATOR_MAX; i++)
771
if(VerifyBuffer((NMemoryAllocatorInterface::id) i, Verbose) != 0)
780
int MemDebug::VerifyPointer(void* pBuf)
782
if(!__GEAR_VALIDATE(pBuf))
785
return VerifyBlock(pBuf, __GEAR_GET_ID(pBuf), false);
788
int MemDebug::VerifyBlock(void* pBuf, NMemoryAllocatorInterface::id AllocId, bool Verbose)
795
if(IsAligned((t_uaddress)pBuf, 4))
797
pHeader = SubstractPointer<dbg_header*>(pBuf, DBG_HDR_SIZE);
799
if(pHeader->Checksum == COMPUTE_CHECKSUM(pHeader))
801
if((AllocId == NMemoryAllocatorInterface::VOID_ALLOC_ID) || (pHeader->AllocId == AllocId))
803
/* Compare bottom flag */
804
if(Memcmp(AddPointer<void*>(pBuf, pHeader->Size),
810
nuxDebugMsg(TEXT("%s(%u): Overflow detected on Buffer #%u [0x%08lx]. Data overwritten at address 0x%08lx\n"),
811
IsBadReadPointer((void*)pHeader->pFileName, sizeof(pHeader->pFileName)) ? TEXT("<Bad Pointer>"):pHeader->pFileName,
815
pHeader->Size + (size_t) pBuf);
826
nuxDebugMsg(TEXT("%s(%u): MemDebug called with wrong allocator on Buffer #%u [0x%08lx] (Id=%u instead of Id=%u)\n"),
827
IsBadReadPointer((void*)pHeader->pFileName, sizeof(pHeader->pFileName)) ? TEXT("<Bad Pointer>"):pHeader->pFileName,
836
Ret = WrongAllocator;
841
if((pHeader->AllocId == AllocId) && (GET_STATUS(pHeader) == STATUS_FREE))
845
nuxDebugMsg(TEXT("%s(%u): MemDebug called with a freed buffer #%u [0x%08lx] <double free?>\n"),
846
IsBadReadPointer((void*)pHeader->pFileName, sizeof(pHeader->pFileName)) ? TEXT("<Bad Pointer>"):pHeader->pFileName,
859
nuxDebugMsg(TEXT("MemDebug detects a corrupted header for buffer #%u [0x%08lx] - Checksum: 0x%08X <memory spill?>\n"),
862
(t_u32)COMPUTE_CHECKSUM(pHeader));
874
nuxDebugMsg(TEXT("MemDebug detects an unaligned pointer for buffer [0x%08lx]\n"),
885
nuxDebugMsg(TEXT("MemDebug called with a NULL pointer\n"));
894
unsigned MemDebug::GetWastedMemory(const void* pData) const
898
if (!pData || !IsAligned((t_uaddress)pData,4))
901
pHeader = SubstractPointer<dbg_header*>((void*)pData, DBG_HDR_SIZE);
902
nuxAssert(pHeader->Checksum == COMPUTE_CHECKSUM(pHeader));
904
t_uaddress returnValue = GetBufferPatternLengthReverse( (const t_u8*)pData, FILL_VALUE, pHeader->Size);
906
//just to make sure we don't have some silly overflow on 64-bit addresses and we can safely cast the result
907
nuxAssert(returnValue < 0xFFFFFFFF);
909
return (unsigned)returnValue;
912
t_u32 MemDebug::GetAllocationNumber(const void *pData) const
914
if (!pData || !IsAligned((t_uaddress)pData,4))
918
dbg_header* pHeader = SubstractPointer<dbg_header*>((void*)pData, DBG_HDR_SIZE);
919
return pHeader->SequenceNo;
922
void MemDebug::SetOnAllocCallback(MemDebug::OnAllocCallbackType callback)
924
NScopeLock Scope(&m_Lock);
925
OnAllocCallback = callback;
928
void MemDebug::SetOnFreeCallback(MemDebug::OnFreeCallbackType callback)
930
NScopeLock Scope(&m_Lock);
931
OnFreeCallback = callback;
936
//////////////////////////////////////////////////////////////////////////
938
// This way, we avoid side-effects when compiling onefiletorulethemall.cpp
939
#undef COMPUTE_CHECKSUM
941
#undef DBG_OVERHEAD_SIZE
942
#undef DBG_TRAILER_SIZE
944
#undef FULL_FILL_VALUE
946
#undef GET_ALLOCATION_TYPE
949
#undef SET_ALLOCATION_TYPE
955
#undef __GEAR_VALIDATE
956
//////////////////////////////////////////////////////////////////////////