~hikiko/nux/arb-srgba-shader

« back to all changes in this revision

Viewing changes to NuxCore/Memory/NMemoryDebugHook.cpp

  • Committer: Neil Jagdish Patel
  • Date: 2010-09-01 19:25:37 UTC
  • Revision ID: neil.patel@canonical.com-20100901192537-mfz7rm6q262pewg6
Import and build NuxCore

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "../NKernel.h"
 
2
#include "../Math/MathUtility.h"
 
3
#include "../DataStruct/NList.h"
 
4
#include "NMemoryDebugHook.h"
 
5
 
 
6
// optional dependency
 
7
#ifdef GEAR_CFG_USE_MEMPAGEHOOK_STUB        
 
8
#include GEAR_INCLUDE_MEMPAGEHOOK_STUB
 
9
 
 
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)
 
13
#else
 
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
 
17
#endif
 
18
 
 
19
 
 
20
NAMESPACE_BEGIN
 
21
 
 
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) 
 
26
{
 
27
    bool isBad = true;
 
28
    t_u8* ptr8 = (t_u8*)ptr;
 
29
    t_u8 val;
 
30
#ifdef _WIN32
 
31
    __try
 
32
#endif
 
33
    {        
 
34
        for(t_u32 i=0; i < memSize; i++)
 
35
            val = *(ptr8+i);
 
36
        isBad = false;
 
37
    }    
 
38
#ifdef _WIN32
 
39
    __except (EXCEPTION_EXECUTE_HANDLER) 
 
40
    {
 
41
    }
 
42
#endif
 
43
    return isBad;
 
44
}
 
45
 
 
46
bool IsBadWritePointer(void* ptr, t_u32 memSize)
 
47
{
 
48
    bool isBad = true;
 
49
    t_u8* ptr8 = (t_u8*)ptr;
 
50
    t_u8 val;
 
51
#ifdef _WIN32
 
52
    __try
 
53
#endif
 
54
    {        
 
55
        for(t_u32 i=0; i < memSize; i++)
 
56
        {
 
57
            val = *(ptr8+i);
 
58
            *(ptr8+i) = val;
 
59
        }
 
60
        isBad = false;
 
61
    }    
 
62
#ifdef _WIN32
 
63
    __except (EXCEPTION_EXECUTE_HANDLER) 
 
64
    {
 
65
    }
 
66
#endif
 
67
 
 
68
    return isBad;
 
69
}
 
70
#pragma optimize("", on)
 
71
 
 
72
 
 
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)
 
75
{
 
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;
 
79
 
 
80
    //we do the first bytes up until alignment
 
81
    while(pIndex < rounded && pIndex < endOfBuffer && (*pIndex == value))
 
82
    {
 
83
        pIndex++;
 
84
    }
 
85
 
 
86
    if(*pIndex == value && pIndex < endOfBuffer) //we go till the end!
 
87
    {
 
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;
 
90
        pIndex = rounded;
 
91
        rounded = (const t_u8*) INL_ADDRESS_TO_PTR(RoundDown(INL_PTR_TO_ADDRESS(endOfBuffer), sizeof(t_word)));
 
92
 
 
93
        while((*(t_word*)pIndex) == fullFillValue && pIndex < rounded)
 
94
            pIndex+= sizeof(t_word);
 
95
 
 
96
        //we do the last part
 
97
        while(*pIndex == value && (char*)pIndex < (char*)endOfBuffer)
 
98
            pIndex++;
 
99
    }
 
100
 
 
101
    return static_cast<t_uaddress>(DiffPointer((void*)pIndex, (void*)startOfBuffer));
 
102
}
 
103
 
 
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)
 
106
{
 
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;
 
110
 
 
111
    //We perform the first check on unaligned bytes
 
112
    while(pIndex >= rounded && *pIndex == value && pIndex >= startOfBuffer)
 
113
    {
 
114
        pIndex--;
 
115
    }
 
116
 
 
117
    if(*pIndex == value && pIndex >= startOfBuffer)
 
118
    {
 
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;
 
121
 
 
122
        pIndex = rounded - sizeof(t_word);
 
123
        rounded = (const t_u8*) INL_ADDRESS_TO_PTR(RoundUp(INL_PTR_TO_ADDRESS(startOfBuffer), sizeof(t_word)));
 
124
 
 
125
        while((*(t_word*)pIndex) == fullFillValue && pIndex >= rounded)
 
126
            pIndex-= sizeof(t_word);
 
127
 
 
128
        //we do the last part
 
129
        pIndex += sizeof(t_word)-1;
 
130
        while(*pIndex == value && pIndex >= startOfBuffer)
 
131
            pIndex--;
 
132
    }
 
133
 
 
134
    return static_cast<t_uaddress>(DiffPointer((void*)endOfBuffer, (void*)pIndex)-1);
 
135
}
 
136
 
 
137
INL_IMPLEMENT_GLOBAL_OBJECT(MemDebug)
 
138
 
 
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;
 
143
 
 
144
#define INL_DEFAULT_MEM_ALIGN           16
 
145
 
 
146
    // Definitions
 
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
 
152
 
 
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)
 
156
 
 
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)
 
163
 
 
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)
 
166
 
 
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))
 
169
 
 
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;
 
175
 
 
176
void MemDebug::Constructor(void) 
 
177
{    
 
178
    m_SequenceNoServer      = 0;    // Sequence start with 0
 
179
    m_LeakThresholdSeqNo    = 0;    // By default threshold = 0
 
180
 
 
181
    // Clear tables
 
182
    for(unsigned i = 0; i < INL_NB_ALLOCATOR_MAX; i++)
 
183
    {        
 
184
        m_AllocatorTbl[i].FailureDelay    = 0;
 
185
        m_AllocatorTbl[i].FailureCount    = 0;
 
186
    }
 
187
 
 
188
    // Register 
 
189
    if(1)
 
190
        m_pNextHook = INL_GLOBAL_OBJECT_INSTANCE(MemHook).Hook(this);
 
191
 
 
192
    OnAllocCallback = NULL;
 
193
    OnFreeCallback = NULL;
 
194
}
 
195
 
 
196
void MemDebug::Destructor(void)
 
197
{
 
198
    VerifyLeakAll();
 
199
 
 
200
    // Unregister 
 
201
    if(m_pNextHook)
 
202
    {
 
203
        INL_GLOBAL_OBJECT_INSTANCE(MemHook).UnHook(this, m_pNextHook);
 
204
        m_pNextHook = 0;
 
205
    }
 
206
}
 
207
 
 
208
void MemDebug::AllocatorDestruction(NMemoryAllocatorInterface& Allocator)
 
209
{
 
210
    NMemoryAllocatorInterface::id AllocId = Allocator.GetId();
 
211
    nuxAssert(AllocId < INL_NB_ALLOCATOR_MAX);
 
212
 
 
213
    VerifyLeak(AllocId);
 
214
    m_AllocatorTbl[AllocId].AllocatedList.Clear();
 
215
 
 
216
    MemoryHook::AllocatorDestruction(Allocator);
 
217
}
 
218
 
 
219
void* MemDebug::Alloc
 
220
    ( 
 
221
    int             OpId,
 
222
    unsigned        Size, 
 
223
    NMemoryAllocatorInterface&   Allocator, 
 
224
    const void*     pParent, 
 
225
    const char*     pId,
 
226
    const char*     pObjType,
 
227
    t_u32             LineNo,
 
228
    const TCHAR*     pFileName
 
229
    )
 
230
{
 
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);
 
233
}
 
234
 
 
235
void* MemDebug::AllocAligned
 
236
    ( 
 
237
    int             OpId,
 
238
    unsigned        Size, 
 
239
    unsigned        Alignment,
 
240
    NMemoryAllocatorInterface&   Allocator, 
 
241
    const void*     pParent, 
 
242
    const char*     pId,
 
243
    const char*     pObjType,
 
244
    t_u32             LineNo,
 
245
    const TCHAR*     pFileName
 
246
    )
 
247
{
 
248
    void* pData = 0;
 
249
 
 
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))
 
254
    {
 
255
        INL_HARDWARE_BREAK;
 
256
    }
 
257
 
 
258
    if(!VerifyAllocFailure(Allocator.GetId()))
 
259
    {
 
260
        if(Alignment <= INL_DEFAULT_MEM_ALIGN)
 
261
        {
 
262
            pData = MemoryHook::Alloc(  OpId, 
 
263
                CalculateDebugSize(Size, Alignment),
 
264
                Allocator,
 
265
                pParent,
 
266
                pId,
 
267
                pObjType,
 
268
                LineNo,
 
269
                pFileName);
 
270
        }else
 
271
        {
 
272
            pData = MemoryHook::AllocAligned(  OpId, 
 
273
                CalculateDebugSize(Size, Alignment),
 
274
                Alignment,
 
275
                Allocator,
 
276
                pParent,
 
277
                pId,
 
278
                pObjType,
 
279
                LineNo,
 
280
                pFileName);               
 
281
        }
 
282
        if(pData) 
 
283
        {   
 
284
            pData = SecondStageAlloc(   pData, 
 
285
                OpId,
 
286
                Size, 
 
287
                Alignment, //Alignment
 
288
                Allocator.GetId(),                                                                                          
 
289
                LineNo, 
 
290
                pFileName,
 
291
                m_SequenceNoServer++);
 
292
        }
 
293
    }
 
294
 
 
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))) 
 
299
    {
 
300
        INL_HARDWARE_BREAK;
 
301
    }
 
302
 
 
303
    if (OnAllocCallback != NULL)
 
304
    {
 
305
        (*OnAllocCallback)(pData, Size);
 
306
    }
 
307
    return(pData);
 
308
}
 
309
 
 
310
void* MemDebug::Realloc
 
311
    ( 
 
312
    void*           pOldPtr, 
 
313
    unsigned        Size,
 
314
    NMemoryAllocatorInterface&   Allocator, 
 
315
    t_u32             LineNo,
 
316
    const TCHAR*     pFileName
 
317
    )
 
318
{
 
319
    //we need to, at least, satisfies the allocator alignment
 
320
    return ReallocAligned(pOldPtr, Size, INL_DEFAULT_MEM_ALIGN, Allocator, LineNo, pFileName);
 
321
}
 
322
 
 
323
void* MemDebug::ReallocAligned
 
324
    ( 
 
325
    void*           pOldPtr, 
 
326
    unsigned        Size,
 
327
    unsigned        Alignment,
 
328
    NMemoryAllocatorInterface&   Allocator, 
 
329
    t_u32             LineNo,
 
330
    const TCHAR*     pFileName
 
331
    )
 
332
{
 
333
    void*           pResult = 0;
 
334
 
 
335
    int Ret = 0;
 
336
 
 
337
    if(pOldPtr)
 
338
    {
 
339
        Ret = VerifyBlock(pOldPtr, Allocator.GetId());
 
340
    }
 
341
 
 
342
    // If the current block is valid...
 
343
    if(Ret == 0)
 
344
    {
 
345
 
 
346
        // Find our header
 
347
        dbg_header* pHeader = NULL;
 
348
 
 
349
        if(pOldPtr)
 
350
        {
 
351
            pHeader = SubstractPointer<dbg_header*>(pOldPtr, DBG_HDR_SIZE);
 
352
 
 
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))
 
358
            {
 
359
                INL_HARDWARE_BREAK;
 
360
            }
 
361
        }
 
362
 
 
363
        if(Size)
 
364
        {
 
365
            if(!VerifyAllocFailure(Allocator.GetId()))
 
366
            {
 
367
                if(Alignment  <= (unsigned)(1 << GetLowerPowerOfTwoExponent(INL_DEFAULT_MEM_ALIGN)))
 
368
                {
 
369
                    pResult = MemoryHook::Alloc(INL_MEMOP_ALLOC, 
 
370
                        CalculateDebugSize(Size,Alignment),
 
371
                        Allocator,
 
372
                        0,
 
373
                        0,
 
374
                        0,
 
375
                        LineNo,
 
376
                        pFileName);   
 
377
                }else
 
378
                {
 
379
                    pResult = MemoryHook::AllocAligned(INL_MEMOP_ALLOC, 
 
380
                        CalculateDebugSize(Size,Alignment),
 
381
                        Alignment,
 
382
                        Allocator,
 
383
                        0,
 
384
                        0,
 
385
                        0,
 
386
                        LineNo,
 
387
                        pFileName);   
 
388
                }
 
389
 
 
390
 
 
391
                if(pResult) 
 
392
                {   
 
393
                    pResult = SecondStageAlloc(pResult, 
 
394
                        INL_MEMOP_ALLOC,
 
395
                        Size, 
 
396
                        Alignment,
 
397
                        Allocator.GetId(),                                                                                          
 
398
                        LineNo, 
 
399
                        pFileName,
 
400
#if GEAR_CFG_MEM_DEBUG_ALLOCNUMBER_INCREMENT_ON_REALLOC == GEAR_ENABLE
 
401
                        m_SequenceNoServer++);
 
402
#else
 
403
                        pHeader->SequenceNo);
 
404
#endif
 
405
                }
 
406
            }
 
407
 
 
408
        }
 
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))) 
 
413
        {
 
414
            INL_HARDWARE_BREAK;
 
415
        }
 
416
 
 
417
        if(pOldPtr)
 
418
        {
 
419
            if(Size && pResult)
 
420
            {
 
421
                // Copy the data
 
422
                Memcpy(pResult, pOldPtr, Min(Size, (unsigned) pHeader->Size));
 
423
            }
 
424
 
 
425
            // Free the old one
 
426
            Free(INL_MEMOP_FREE, pOldPtr, Allocator, LineNo, pFileName);
 
427
        }
 
428
    }
 
429
 
 
430
    return(pResult);
 
431
}
 
432
 
 
433
//
 
434
// VerifyAllocFailure 
 
435
// Returns true when we must simulate an allocation failure
 
436
//
 
437
bool MemDebug::VerifyAllocFailure
 
438
    (
 
439
    NMemoryAllocatorInterface::id        AllocId
 
440
    )
 
441
{    
 
442
    nuxAssert(AllocId < INL_NB_ALLOCATOR_MAX);
 
443
 
 
444
    NScopeLock Scope(&m_Lock);
 
445
    if(m_AllocatorTbl[AllocId].FailureDelay > 0)
 
446
    {
 
447
        // Decrease the delay before verifying if failure occur
 
448
        m_AllocatorTbl[AllocId].FailureDelay--;
 
449
    }
 
450
    else
 
451
    {
 
452
        // Delay expired, How many fail must be done?
 
453
        if(m_AllocatorTbl[AllocId].FailureCount > 0) 
 
454
        {
 
455
            m_AllocatorTbl[AllocId].FailureCount--;
 
456
            return(true);
 
457
        }
 
458
    }
 
459
 
 
460
    return(false);
 
461
}
 
462
 
 
463
t_u32 MemDebug::CalculateDebugSize(t_u32 Size, t_u32 Alignment) const
 
464
{
 
465
    return Size + RoundUp(DBG_HDR_SIZE, Alignment)  + DBG_TRAILER_SIZE;
 
466
}
 
467
 
 
468
void* MemDebug::SecondStageAlloc(
 
469
                                 void*                   pData,
 
470
                                 int                     optId,
 
471
                                 unsigned                Size, 
 
472
                                 unsigned                Alignment,
 
473
                                 NMemoryAllocatorInterface::id        AllocId, 
 
474
                                 t_u32                   LineNo,
 
475
                                 const TCHAR*            pFileName,
 
476
                                 t_u32                   sequenceNo)
 
477
{
 
478
    nuxAssert(pData);
 
479
    nuxAssert(IsAligned((t_uaddress)pData, 4));
 
480
 
 
481
 
 
482
    dbg_header* pHeader = (dbg_header*) pData;
 
483
 
 
484
    if(DBG_HDR_SIZE != RoundUp(DBG_HDR_SIZE, Alignment)) //we need to offset everything
 
485
    {
 
486
        void* offsetData = AddPointer<void*>(pData, RoundUp(DBG_HDR_SIZE, Alignment));
 
487
        pHeader = SubstractPointer<dbg_header*>(offsetData, DBG_HDR_SIZE);  
 
488
    }
 
489
 
 
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
 
495
    // Block status
 
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
 
499
 
 
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
 
503
 
 
504
    // Compute the checksum on header
 
505
    pHeader->Checksum     = COMPUTE_CHECKSUM(pHeader);
 
506
 
 
507
    // Fill buffer with traceable value...
 
508
    Memset(AddPointer<void*>(pHeader, DBG_HDR_SIZE),
 
509
        FILL_VALUE, 
 
510
        Size);
 
511
 
 
512
    /* Set bottom flag */
 
513
    Memcpy(AddPointer<void*>(pHeader, DBG_HDR_SIZE + Size),
 
514
        &BOTTOM_FLAG, 
 
515
        DBG_TRAILER_SIZE);
 
516
 
 
517
    // Enter the critical section to ad this buffer at the end of the 
 
518
    // double linked-list of allocated blocks.
 
519
    m_Lock.Lock();
 
520
 
 
521
    m_AllocatorTbl[AllocId].AllocatedList.PushBack(*pHeader);
 
522
 
 
523
    m_Lock.Unlock();
 
524
 
 
525
    /* Move right after the current header (to user zone) */
 
526
    return(AddPointer<void*>(pHeader, DBG_HDR_SIZE)); 
 
527
}    
 
528
 
 
529
 
 
530
void MemDebug::Free
 
531
    (
 
532
    int                 OpId,
 
533
    void*               pData, 
 
534
    NMemoryAllocatorInterface&       Allocator,
 
535
    t_u32               LineNo,
 
536
    const TCHAR*        pFileName
 
537
    )
 
538
{    
 
539
    if(pData && VerifyBlock(pData, Allocator.GetId()) == 0)
 
540
    {
 
541
        NScopeLock Scope(&m_Lock);
 
542
        FreeBlock(OpId, pData, Allocator, LineNo, pFileName);
 
543
    }
 
544
}
 
545
 
 
546
t_u32 MemDebug::GetAllocatedSize
 
547
    (
 
548
    void*           pData,     
 
549
    NMemoryAllocatorInterface&   Allocator, 
 
550
    t_u32*            pRetHeaderSize    
 
551
    ) const
 
552
 
553
    t_u32 Result = 0;
 
554
 
 
555
    if(pData)
 
556
    {
 
557
        dbg_header* pHeader = SubstractPointer<dbg_header*>(pData, DBG_HDR_SIZE);
 
558
 
 
559
        void * ptr = (void*)pHeader;
 
560
        t_u32 alignment = GET_ALIGNMENT(pHeader);
 
561
 
 
562
        if(alignment > DBG_HDR_SIZE)
 
563
        {
 
564
            ptr = SubstractPointer<void*>(pData, alignment);
 
565
        }
 
566
 
 
567
        Result = MemoryHook::GetAllocatedSize(ptr, Allocator, pRetHeaderSize);
 
568
 
 
569
        if(Result)
 
570
        {
 
571
            if(pRetHeaderSize)
 
572
                *pRetHeaderSize += Max(DBG_HDR_SIZE, alignment);
 
573
        }
 
574
    }
 
575
 
 
576
    return Result;
 
577
}
 
578
 
 
579
unsigned MemDebug::GetDebugOverHead(unsigned alignment) const
 
580
{
 
581
    return CalculateDebugSize(0, alignment) + MemoryHook::GetDebugOverHead(alignment);
 
582
}
 
583
 
 
584
 
 
585
void MemDebug::FreeBlock
 
586
    (
 
587
    int                 OpId,
 
588
    void*               pData, 
 
589
    NMemoryAllocatorInterface&       Allocator,
 
590
    t_u32               LineNo,
 
591
    const TCHAR*        pFileName
 
592
    )
 
593
{
 
594
    nuxAssert(pData);
 
595
 
 
596
    dbg_header* pHeader = SubstractPointer<dbg_header*>(pData, DBG_HDR_SIZE);       
 
597
 
 
598
    if(GET_STATUS(pHeader) == STATUS_ALLOC)
 
599
    {
 
600
        if (OnFreeCallback != NULL)
 
601
        {
 
602
            (*OnFreeCallback)(pData, pHeader->Size);
 
603
        }
 
604
 
 
605
        m_AllocatorTbl[Allocator.GetId()].AllocatedList.Remove(*pHeader);
 
606
 
 
607
        //Check if the Block was deleted with the correct operator
 
608
 
 
609
        if(GET_ALLOCATION_TYPE(pHeader) != OpId - (INL_MEMOP_FREE - INL_MEMOP_ALLOC))
 
610
        {
 
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),
 
613
                pHeader->LineNo,
 
614
                pHeader->SequenceNo,
 
615
                (size_t) pData,
 
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[]"))),
 
618
                pFileName,
 
619
                LineNo,
 
620
                ((OpId == INL_MEMOP_FREE) ? TEXT("Free") : ((OpId == INL_MEMOP_DELETE) ? TEXT("Delete") : TEXT("Delete[]")))
 
621
                );
 
622
 
 
623
            INL_HARDWARE_BREAK;
 
624
        }
 
625
 
 
626
        SET_STATUS(pHeader, STATUS_FREE);
 
627
        pHeader->pFileName      = pFileName;
 
628
        pHeader->LineNo         = (t_u16) LineNo;
 
629
 
 
630
        /* Recompute the checksum on header */
 
631
        pHeader->Checksum       = COMPUTE_CHECKSUM(pHeader);
 
632
 
 
633
        Memset(pData, WIPE_VALUE, pHeader->Size);           
 
634
 
 
635
        //we get the "real" pointer we allocated
 
636
        pData = SubstractPointer<void*>(pData, RoundUp(DBG_HDR_SIZE, GET_ALIGNMENT(pHeader)));
 
637
 
 
638
        MemoryHook::Free(OpId, pData, Allocator, LineNo, pFileName);
 
639
 
 
640
    }
 
641
    else 
 
642
    {
 
643
        NFileName filename = pFileName;
 
644
        nuxDebugMsg(TEXT("Buffer freed 2 times (0x%08lx), %s, LINE %u\n"), (size_t) pData, filename.GetCleanFilename().GetTCharPtr(), LineNo);
 
645
        INL_HARDWARE_BREAK;
 
646
    }
 
647
}
 
648
 
 
649
// When freeing a marker, we must also free all the block linked after
 
650
void MemDebug::FreeMarker(
 
651
    void*               pMarker, 
 
652
    MemStackInterface&  StackAllocator,
 
653
    t_u32               LineNo,
 
654
    const TCHAR*         pFileName
 
655
    )
 
656
{
 
657
    nuxAssert(pMarker);
 
658
 
 
659
    NListNoDyn<dbg_header>*    pRoot =  &m_AllocatorTbl[StackAllocator.GetId()].AllocatedList;
 
660
 
 
661
    NScopeLock Scope(&m_Lock);
 
662
    while(pRoot->Back() >= pMarker)
 
663
    {   
 
664
        void* pData = AddPointer<void*>(pRoot->Back(), DBG_HDR_SIZE);
 
665
        int   Ret   = VerifyBlock(pData, StackAllocator);
 
666
        if(Ret == 0)
 
667
        {        
 
668
 
 
669
            FreeBlock(GET_ALLOCATION_TYPE(pRoot->Back()) + (INL_MEMOP_FREE - INL_MEMOP_ALLOC) , pData, StackAllocator, LineNo, pFileName);
 
670
        }
 
671
    }
 
672
 
 
673
    // Free the real memory
 
674
    MemoryHook::FreeMarker(pMarker, StackAllocator, LineNo, pFileName);
 
675
}
 
676
 
 
677
void MemDebug::SetAllocFailure
 
678
    (   
 
679
    const NMemoryAllocatorInterface&     Allocator, 
 
680
    unsigned                Delay,
 
681
    unsigned                NbFailure
 
682
    )
 
683
{
 
684
    NMemoryAllocatorInterface::id     Id = Allocator.GetId();
 
685
    nuxAssert(Id < INL_NB_ALLOCATOR_MAX);
 
686
 
 
687
    NScopeLock Scope(&m_Lock);
 
688
 
 
689
    m_AllocatorTbl[Id].FailureDelay = Delay;
 
690
    m_AllocatorTbl[Id].FailureCount = NbFailure;    
 
691
}
 
692
 
 
693
unsigned MemDebug::VerifyLeak(NMemoryAllocatorInterface::id AllocId, bool Verbose)
 
694
{
 
695
    dbg_header* pHeader;
 
696
    void*               pMemFault;
 
697
    unsigned    Result = 0;
 
698
 
 
699
    nuxAssert(AllocId < INL_NB_ALLOCATOR_MAX);
 
700
 
 
701
    NScopeLock Scope(&m_Lock);
 
702
 
 
703
    NListNoDyn<dbg_header>::DIterator Iterator(m_AllocatorTbl[AllocId].AllocatedList);
 
704
 
 
705
    while(!Iterator.Empty())
 
706
    {
 
707
        pHeader = (dbg_header*) Iterator.Current();
 
708
        pMemFault = AddPointer<void*>(pHeader, DBG_HDR_SIZE);
 
709
 
 
710
        if(pHeader->SequenceNo >= m_LeakThresholdSeqNo)
 
711
        {
 
712
            if(Verbose)
 
713
            {
 
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,
 
716
                    pHeader->LineNo, 
 
717
                    pHeader->Size,
 
718
                    pMemFault,
 
719
                    pHeader->SequenceNo);                               
 
720
            }
 
721
 
 
722
            Result++;
 
723
        }
 
724
 
 
725
        ++Iterator;        
 
726
    }    
 
727
 
 
728
    return(Result);
 
729
}
 
730
 
 
731
unsigned MemDebug::VerifyLeakAll(bool Verbose)      
 
732
{
 
733
    unsigned Result = 0;
 
734
 
 
735
    for(unsigned i = 0; i < INL_NB_ALLOCATOR_MAX; i++)
 
736
    {
 
737
        Result += VerifyLeak((NMemoryAllocatorInterface::id) i, Verbose);
 
738
    }
 
739
 
 
740
    return Result;
 
741
}
 
742
 
 
743
 
 
744
int MemDebug::VerifyBuffer(NMemoryAllocatorInterface::id AllocId, bool Verbose)
 
745
{
 
746
    void*       pBuf;
 
747
    int         Result = 0;
 
748
 
 
749
    nuxAssert(AllocId < INL_NB_ALLOCATOR_MAX);
 
750
 
 
751
    NScopeLock Scope(&m_Lock);
 
752
 
 
753
    NListNoDyn<dbg_header>::DIterator Iterator(m_AllocatorTbl[AllocId].AllocatedList);
 
754
 
 
755
    while((!Iterator.Empty()) && (Result == 0))
 
756
    {
 
757
        pBuf = AddPointer<void*>(Iterator.Current(), DBG_HDR_SIZE);
 
758
        Result = VerifyBlock(pBuf, AllocId, Verbose);
 
759
        ++Iterator;
 
760
    }    
 
761
 
 
762
    return Result;
 
763
}
 
764
 
 
765
unsigned MemDebug::VerifyBufferAll(bool Verbose)
 
766
{
 
767
    unsigned Result = 0;
 
768
 
 
769
    for(unsigned i = 0; i < INL_NB_ALLOCATOR_MAX; i++)
 
770
    {
 
771
        if(VerifyBuffer((NMemoryAllocatorInterface::id) i, Verbose) != 0)
 
772
        {
 
773
            Result++;
 
774
        }
 
775
    }
 
776
 
 
777
    return Result;
 
778
}
 
779
 
 
780
int MemDebug::VerifyPointer(void* pBuf)
 
781
{
 
782
    if(!__GEAR_VALIDATE(pBuf))
 
783
        return Invalid;
 
784
 
 
785
    return VerifyBlock(pBuf, __GEAR_GET_ID(pBuf), false);
 
786
}
 
787
 
 
788
int MemDebug::VerifyBlock(void* pBuf, NMemoryAllocatorInterface::id AllocId, bool Verbose)
 
789
{
 
790
    dbg_header* pHeader;
 
791
    int Ret = 0;
 
792
 
 
793
    if(pBuf)
 
794
    {
 
795
        if(IsAligned((t_uaddress)pBuf, 4))
 
796
        {
 
797
            pHeader = SubstractPointer<dbg_header*>(pBuf, DBG_HDR_SIZE);
 
798
 
 
799
            if(pHeader->Checksum == COMPUTE_CHECKSUM(pHeader))
 
800
            {
 
801
                if((AllocId == NMemoryAllocatorInterface::VOID_ALLOC_ID) || (pHeader->AllocId == AllocId))
 
802
                {
 
803
                    /* Compare bottom flag */
 
804
                    if(Memcmp(AddPointer<void*>(pBuf, pHeader->Size), 
 
805
                        &BOTTOM_FLAG, 
 
806
                        DBG_TRAILER_SIZE))
 
807
                    {
 
808
                        if(Verbose) 
 
809
                        {
 
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,
 
812
                                pHeader->LineNo,
 
813
                                pHeader->SequenceNo,
 
814
                                (size_t) pBuf,
 
815
                                pHeader->Size + (size_t) pBuf);
 
816
                            INL_HARDWARE_BREAK;
 
817
                        }
 
818
 
 
819
                        Ret = Overflow;                
 
820
                    }
 
821
                } 
 
822
                else 
 
823
                {
 
824
                    if(Verbose) 
 
825
                    {
 
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,
 
828
                            pHeader->LineNo,
 
829
                            pHeader->SequenceNo,
 
830
                            (size_t) pBuf,
 
831
                            AllocId,
 
832
                            pHeader->AllocId);
 
833
                        INL_HARDWARE_BREAK;
 
834
                    }
 
835
 
 
836
                    Ret = WrongAllocator;
 
837
                }
 
838
            } 
 
839
            else 
 
840
            {
 
841
                if((pHeader->AllocId == AllocId) && (GET_STATUS(pHeader) == STATUS_FREE))
 
842
                {
 
843
                    if(Verbose) 
 
844
                    {
 
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,
 
847
                            pHeader->LineNo,
 
848
                            pHeader->SequenceNo,
 
849
                            (size_t) pBuf);
 
850
                        INL_HARDWARE_BREAK;
 
851
                    }
 
852
 
 
853
                    Ret = DoubleFree;
 
854
                }
 
855
                else
 
856
                {
 
857
                    if(Verbose) 
 
858
                    {
 
859
                        nuxDebugMsg(TEXT("MemDebug detects a corrupted header for buffer #%u [0x%08lx] - Checksum: 0x%08X <memory spill?>\n"),
 
860
                            pHeader->SequenceNo,
 
861
                            (size_t) pBuf,
 
862
                            (t_u32)COMPUTE_CHECKSUM(pHeader));
 
863
                        INL_HARDWARE_BREAK;
 
864
                    }
 
865
 
 
866
                    Ret = Corrupted;
 
867
                }
 
868
            }
 
869
        }         
 
870
        else 
 
871
        {
 
872
            if(Verbose) 
 
873
            {
 
874
                nuxDebugMsg(TEXT("MemDebug detects an unaligned pointer for buffer [0x%08lx]\n"),
 
875
                    (size_t) pBuf);
 
876
                INL_HARDWARE_BREAK;
 
877
            }
 
878
            Ret = Unaligned;
 
879
        }
 
880
    } 
 
881
    else 
 
882
    {
 
883
        if(Verbose) 
 
884
        {
 
885
            nuxDebugMsg(TEXT("MemDebug called with a NULL pointer\n"));
 
886
            INL_HARDWARE_BREAK;
 
887
        }
 
888
        Ret = Invalid;
 
889
    }
 
890
 
 
891
    return(Ret);
 
892
}
 
893
 
 
894
unsigned MemDebug::GetWastedMemory(const void* pData) const
 
895
{
 
896
    dbg_header*     pHeader;
 
897
 
 
898
    if (!pData || !IsAligned((t_uaddress)pData,4))
 
899
        return 0;
 
900
 
 
901
    pHeader = SubstractPointer<dbg_header*>((void*)pData, DBG_HDR_SIZE);
 
902
    nuxAssert(pHeader->Checksum == COMPUTE_CHECKSUM(pHeader));
 
903
 
 
904
    t_uaddress returnValue = GetBufferPatternLengthReverse( (const t_u8*)pData, FILL_VALUE, pHeader->Size);
 
905
 
 
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);
 
908
 
 
909
    return (unsigned)returnValue;
 
910
}
 
911
 
 
912
t_u32 MemDebug::GetAllocationNumber(const void *pData) const
 
913
{
 
914
    if (!pData || !IsAligned((t_uaddress)pData,4))
 
915
        return 0;
 
916
 
 
917
    // Find our header
 
918
    dbg_header* pHeader = SubstractPointer<dbg_header*>((void*)pData, DBG_HDR_SIZE);
 
919
    return pHeader->SequenceNo;
 
920
}
 
921
 
 
922
void MemDebug::SetOnAllocCallback(MemDebug::OnAllocCallbackType callback)
 
923
{
 
924
    NScopeLock Scope(&m_Lock);
 
925
    OnAllocCallback = callback;
 
926
}
 
927
 
 
928
void MemDebug::SetOnFreeCallback(MemDebug::OnFreeCallbackType callback)
 
929
{
 
930
    NScopeLock Scope(&m_Lock);
 
931
    OnFreeCallback = callback;
 
932
}
 
933
 
 
934
NAMESPACE_END
 
935
 
 
936
//////////////////////////////////////////////////////////////////////////
 
937
// Undefs section
 
938
// This way, we avoid side-effects when compiling onefiletorulethemall.cpp 
 
939
#undef COMPUTE_CHECKSUM
 
940
#undef DBG_HDR_SIZE
 
941
#undef DBG_OVERHEAD_SIZE
 
942
#undef DBG_TRAILER_SIZE
 
943
#undef FILL_VALUE
 
944
#undef FULL_FILL_VALUE
 
945
#undef GET_ALIGNMENT
 
946
#undef GET_ALLOCATION_TYPE
 
947
#undef GET_STATUS
 
948
#undef SET_ALIGNMENT
 
949
#undef SET_ALLOCATION_TYPE
 
950
#undef SET_STATUS
 
951
#undef STATUS_ALLOC
 
952
#undef STATUS_FREE
 
953
#undef WIPE_VALUE
 
954
#undef __GEAR_GET_ID
 
955
#undef __GEAR_VALIDATE
 
956
//////////////////////////////////////////////////////////////////////////