1//----------------------------------------------------------------------------
2// Anti-Grain Geometry - Version 2.2
3// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
4//
5// Permission to copy, use, modify, sell and distribute this software
6// is granted provided this copyright notice appears in all copies.
7// This software is provided "as is" without express or implied
8// warranty, and with no claim as to its suitability for any purpose.
9//
10//----------------------------------------------------------------------------
11// Contact: mcseem@antigrain.com
12//          mcseemagg@yahoo.com
13//          http://www.antigrain.com
14//----------------------------------------------------------------------------
15//
16// Debuging stuff for catching memory leaks and corruptions
17//
18//----------------------------------------------------------------------------
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <stdarg.h>
23#include "dbg_new/agg_dbg_new.h"
24
25namespace agg
26{
27
28    int dbg_new_level = -1;
29
30    struct dbg_new
31    {
32        unsigned new_count;
33        unsigned del_count;
34        unsigned new_bytes;
35        unsigned del_bytes;
36        unsigned max_count;
37        unsigned max_bytes;
38        unsigned corrupted_count;
39        char     file_name[512];
40        int      line;
41        bool     report_all;
42    };
43
44    dbg_new dbg_new_info[max_dbg_new_level] =
45    {
46        { 0, 0, 0, 0, 0, 0, 0, "", 0, false },
47    };
48
49#ifdef AGG_DBG_NEW_CHECK_ADDR
50    void* dbg_new_allocations[max_allocations] =
51    {
52       0,
53    };
54    unsigned dbg_new_prev_word[max_allocations] =
55    {
56       0,
57    };
58
59
60    unsigned dbg_new_max_count = 0;
61#endif
62
63
64    //------------------------------------------------------------------------
65    void add_allocated_addr(void* ptr)
66    {
67#ifdef AGG_DBG_NEW_CHECK_ADDR
68        if(dbg_new_max_count >= max_allocations)
69        {
70            printf("ADDR_CHECK: limit exceeded\n");
71        }
72        dbg_new_allocations[dbg_new_max_count] = ptr;
73        memcpy(dbg_new_prev_word + dbg_new_max_count,
74               ((char*)ptr) - sizeof(unsigned),
75               sizeof(unsigned));
76        dbg_new_max_count++;
77#endif
78    }
79
80
81    //------------------------------------------------------------------------
82    bool check_and_remove_allocated_addr(void* ptr)
83    {
84#ifdef AGG_DBG_NEW_CHECK_ADDR
85        unsigned i;
86        for(i = 0; i < dbg_new_max_count; i++)
87        {
88            if(dbg_new_allocations[i] == ptr)
89            {
90                unsigned prev;
91                memcpy(&prev,
92                       ((char*)ptr) - sizeof(unsigned),
93                       sizeof(unsigned));
94
95                if(prev != dbg_new_prev_word[i])
96                {
97                    printf("MEMORY CORRUPTION AT %08x prev=%08x cur=%08x\n", ptr, prev, dbg_new_prev_word[i]);
98                    //return false;
99                }
100
101                if(i < dbg_new_max_count - 1)
102                {
103                   memmove(dbg_new_allocations + i,
104                           dbg_new_allocations + i + 1,
105                           sizeof(void*) * dbg_new_max_count - i - 1);
106                }
107                dbg_new_max_count--;
108                //printf("free ok\n");
109                return true;
110            }
111        }
112        printf("ATTEMPT TO FREE BAD ADDRESS %08x\n", ptr);
113        return false;
114#else
115        return true;
116#endif
117    }
118
119
120    //------------------------------------------------------------------------
121    watchdoggy::watchdoggy(const char* file, int line, bool report_all)
122    {
123        #ifdef _WIN32
124        if(dbg_new_level == -1)
125        {
126           FILE* fd = fopen("stdout.txt", "w");
127           fclose(fd);
128        }
129        #endif
130
131        dbg_new_level++;
132        ::memset(dbg_new_info + dbg_new_level, 0, sizeof(dbg_new));
133        if(file == 0) file = "";
134        int len = strlen(file);
135        if(len > 511) len = 511;
136        ::memcpy(dbg_new_info[dbg_new_level].file_name, file, len);
137        dbg_new_info[dbg_new_level].file_name[len] = 0;
138        dbg_new_info[dbg_new_level].line = line;
139        dbg_new_info[dbg_new_level].report_all = report_all;
140        printf("wd%d started. File:%s line:%d\n",
141                dbg_new_level,
142                file,
143                line);
144    }
145
146
147    //------------------------------------------------------------------------
148    watchdoggy::~watchdoggy()
149    {
150        if(dbg_new_level >= 0)
151        {
152            printf("wd%d stopped. File:%s line:%d\n",
153                    dbg_new_level,
154                    dbg_new_info[dbg_new_level].file_name,
155                    dbg_new_info[dbg_new_level].line);
156            printf("new_count=%u del_count=%u max_count=%u balance=%d\n"
157                   "new_bytes=%u del_bytes=%u max_bytes=%u balance=%d "
158                   "corrupted_count=%u\n",
159                    dbg_new_info[dbg_new_level].new_count,
160                    dbg_new_info[dbg_new_level].del_count,
161                    dbg_new_info[dbg_new_level].max_count,
162                    int(dbg_new_info[dbg_new_level].new_count -
163                        dbg_new_info[dbg_new_level].del_count),
164                    dbg_new_info[dbg_new_level].new_bytes,
165                    dbg_new_info[dbg_new_level].del_bytes,
166                    dbg_new_info[dbg_new_level].max_bytes,
167                    int(dbg_new_info[dbg_new_level].new_bytes -
168                        dbg_new_info[dbg_new_level].del_bytes),
169                    dbg_new_info[dbg_new_level].corrupted_count
170            );
171            dbg_new_level--;
172        }
173    }
174
175
176    //------------------------------------------------------------------------
177    //
178    // This code implements the AUTODIN II polynomial
179    // The variable corresponding to the macro argument "crc" should
180    // be an unsigned long.
181    // Oroginal code  by Spencer Garrett <srg@quick.com>
182    //
183    // generated using the AUTODIN II polynomial
184    //	x^32 + x^26 + x^23 + x^22 + x^16 +
185    //	x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
186    //
187    //------------------------------------------------------------------------
188    static const unsigned crc32tab[256] =
189    {
190	    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
191	    0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
192	    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
193	    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
194	    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
195	    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
196	    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
197	    0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
198	    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
199	    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
200	    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
201	    0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
202	    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
203	    0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
204	    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
205	    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
206
207	    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
208	    0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
209	    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
210	    0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
211	    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
212	    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
213	    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
214	    0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
215	    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
216	    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
217	    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
218	    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
219	    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
220	    0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
221	    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
222	    0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
223
224	    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
225	    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
226	    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
227	    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
228	    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
229	    0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
230	    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
231	    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
232	    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
233	    0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
234	    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
235	    0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
236	    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
237	    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
238	    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
239	    0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
240
241	    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
242	    0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
243	    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
244	    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
245	    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
246	    0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
247	    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
248	    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
249	    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
250	    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
251	    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
252	    0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
253	    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
254	    0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
255	    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
256	    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
257    };
258
259
260    //------------------------------------------------------------------------
261    static unsigned long calcCRC32(const char* buf, unsigned size)
262    {
263       unsigned long crc = (unsigned long)~0;
264       const char* p;
265       unsigned len = 0;
266       unsigned nr = size;
267
268       for (len += nr, p = buf; nr--; ++p)
269       {
270          crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff];
271       }
272       return ~crc;
273    }
274
275
276
277
278
279    //------------------------------------------------------------------------
280    void* dbg_malloc(unsigned size, const char* file, int line)
281    {
282        if(dbg_new_level < 0)
283        {
284            void* ptr = ::malloc(size);
285            printf("%u allocated at %08x %s %d\n", size, ptr, file, line);
286            add_allocated_addr(ptr);
287            return ptr;
288        }
289
290        // The structure of the allocated memory:
291        //
292        // [USER_SIZE:16 bytes]   //allows for keeping proper data alignment
293        // [USER_MEM]
294        // [CRC32_sum:long, actual size depends on architecture]
295        // [test_bytes:256 bytes] //should be enough for checking non-fatal
296        //                        //corruptions with keeping the line number
297        //                        //and filename correct
298        // [line:unsigned]
299        // [strlen:unsigned]
300        // [file_name:zero_end_string]
301
302        unsigned fname_len = ::strlen(file) + 1;
303        unsigned total_size = 16 +                    // size
304                              size +                  // user_mem
305                              sizeof(unsigned long) + // crc32
306                              256 +                   // zero_bytes
307                              sizeof(unsigned) +      // line
308                              sizeof(unsigned) +      // strlen
309                              fname_len;              // .cpp file_name
310
311        char* inf_ptr = (char*)::malloc(total_size);
312        char* ret_ptr = inf_ptr + 16;
313
314        int i;
315        for(i = 0; i < 16; i++)
316        {
317            inf_ptr[i] = (char)(15-i);
318        }
319        ::memcpy(inf_ptr, &size, sizeof(unsigned));
320
321        unsigned long crc32_before = calcCRC32(inf_ptr, 16);
322
323        inf_ptr += 16 + size;
324        char* crc32_ptr = inf_ptr;
325        inf_ptr += sizeof(unsigned long);
326
327        for(i = 0; i < 256; i++)
328        {
329            *inf_ptr++ = (char)(255-i);
330        }
331
332        ::memcpy(inf_ptr, &line, sizeof(unsigned));
333        inf_ptr += sizeof(unsigned);
334
335        ::memcpy(inf_ptr, &fname_len, sizeof(unsigned));
336        inf_ptr += sizeof(unsigned);
337
338        ::strcpy(inf_ptr, file);
339
340        unsigned long // long just in case
341            crc32_sum = calcCRC32(crc32_ptr + sizeof(unsigned long),
342                                  256 +
343                                  sizeof(unsigned) +
344                                  sizeof(unsigned) +
345                                  fname_len);
346
347        crc32_sum ^= crc32_before;
348
349        ::memcpy(crc32_ptr, &crc32_sum, sizeof(unsigned long));
350
351        dbg_new_info[dbg_new_level].new_count++;
352        dbg_new_info[dbg_new_level].new_bytes += size;
353        int balance = int(dbg_new_info[dbg_new_level].new_count -
354                          dbg_new_info[dbg_new_level].del_count);
355
356        if(balance > 0)
357        {
358            if(balance > int(dbg_new_info[dbg_new_level].max_count))
359            {
360                dbg_new_info[dbg_new_level].max_count = unsigned(balance);
361            }
362        }
363
364
365        balance = int(dbg_new_info[dbg_new_level].new_bytes -
366                      dbg_new_info[dbg_new_level].del_bytes);
367
368        if(balance > 0)
369        {
370            if(balance > int(dbg_new_info[dbg_new_level].max_bytes))
371            {
372                dbg_new_info[dbg_new_level].max_bytes = unsigned(balance);
373            }
374        }
375
376
377        if(dbg_new_info[dbg_new_level].report_all)
378        {
379            printf("wdl%d. %u allocated %08x. %s, %d\n",
380                    dbg_new_level,
381                    size,
382                    ret_ptr,
383                    file,
384                    line
385            );
386        }
387
388        add_allocated_addr(ret_ptr);
389        return ret_ptr;
390    }
391
392
393
394    //------------------------------------------------------------------------
395    void dbg_free(void* ptr)
396    {
397        if(ptr == 0)
398        {
399           //printf("Null pointer free\n");
400           return;
401        }
402
403        if(!check_and_remove_allocated_addr(ptr)) return;
404
405        if(dbg_new_level < 0)
406        {
407            printf("free at %08x\n", ptr);
408            ::free(ptr);
409            return;
410        }
411
412        char* free_ptr = (char*)ptr;
413        char* inf_ptr = free_ptr;
414        free_ptr -= 16;
415
416        unsigned size;
417        ::memcpy(&size, free_ptr, sizeof(unsigned));
418
419        unsigned long crc32_before = calcCRC32(free_ptr, 16);
420
421        inf_ptr += size;
422        unsigned long crc32_sum;
423        ::memcpy(&crc32_sum, inf_ptr, sizeof(unsigned long));
424        inf_ptr += sizeof(unsigned long);
425        char* crc32_ptr = inf_ptr;
426
427        inf_ptr += 256;
428
429        unsigned line;
430        ::memcpy(&line, inf_ptr, sizeof(unsigned));
431        inf_ptr += sizeof(unsigned);
432
433        unsigned fname_len;
434        ::memcpy(&fname_len, inf_ptr, sizeof(unsigned));
435        inf_ptr += sizeof(unsigned);
436
437        char file[512];
438        if(fname_len > 511) fname_len = 511;
439        ::memcpy(file, inf_ptr, fname_len);
440        file[fname_len] = 0;
441
442        if(crc32_sum != (calcCRC32(crc32_ptr,
443                                   256 +
444                                   sizeof(unsigned) +
445                                   sizeof(unsigned) +
446                                   fname_len) ^ crc32_before))
447        {
448            printf("WD%d:MEMORY CORRUPTION AT %08x. Allocated %u bytes in %s, line %d\n",
449                    dbg_new_level,
450                    ptr,
451                    size,
452                    file,
453                    line);
454            dbg_new_info[dbg_new_level].corrupted_count++;
455        }
456        else
457        {
458            ::free(free_ptr);
459
460            dbg_new_info[dbg_new_level].del_count++;
461            dbg_new_info[dbg_new_level].del_bytes += size;
462
463            if(dbg_new_info[dbg_new_level].report_all)
464            {
465                printf("wdl%d. %u freed %08x. %s, %d\n",
466                        dbg_new_level,
467                        size,
468                        free_ptr,
469                        file,
470                        line
471                );
472            }
473        }
474    }
475}
476
477#ifdef new
478#undef new
479#endif
480
481//----------------------------------------------------------------------------
482void* operator new (size_t size, const char* file, int line)
483{
484    return agg::dbg_malloc(size, file, line);
485}
486
487//----------------------------------------------------------------------------
488void* operator new [] (size_t size, const char* file, int line)
489{
490    return agg::dbg_malloc(size, file, line);
491}
492
493//----------------------------------------------------------------------------
494void  operator delete(void *ptr) throw()
495{
496    agg::dbg_free(ptr);
497}
498
499//----------------------------------------------------------------------------
500void  operator delete [] (void *ptr) throw()
501{
502    agg::dbg_free(ptr);
503}
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518/*
519#include "dbg_new/agg_dbg_new.h"
520
521int main()
522{
523    AGG_WATCHDOGGY(wd1, true);
524    int* a = new int[100];
525    a[100] = 0;
526
527    delete [] a;
528    return 0;
529}
530*/
531
532
533
534
535
536
537
538
539