1 /*
2  * Copyright (C) 1997-2004, Michael Jennings
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 /**
25  * @file mem.c
26  * Memory Management Subsystem Source File
27  *
28  * This file contains the memory management subsystem.
29  *
30  * @author Michael Jennings <mej@eterm.org>
31  * $Revision: 1.25 $
32  * $Date: 2005/12/22 23:28:55 $
33  */
34 
35 static const char __attribute__((unused)) cvs_ident[] = "$Id: mem.c,v 1.25 2005/12/22 23:28:55 mej Exp $";
36 
37 #ifdef HAVE_CONFIG_H
38 # include <config.h>
39 #endif
40 
41 #include "libast_internal.h"
42 
43 static void memrec_add_var(memrec_t *, const spif_charptr_t, unsigned long, void *, size_t);
44 static ptr_t *memrec_find_var(memrec_t *, const void *);
45 static void memrec_rem_var(memrec_t *, const spif_charptr_t, const spif_charptr_t, unsigned long, const void *);
46 static void memrec_chg_var(memrec_t *, const spif_charptr_t, const spif_charptr_t, unsigned long, const void *, void *, size_t);
47 static void memrec_dump_pointers(memrec_t *);
48 static void memrec_dump_resources(memrec_t *);
49 
50 #if MALLOC_CALL_DEBUG
51 /*@{*/
52 /**
53  * @name Memory Management Call Tracking
54  * Count calls to memory management functions.
55  *
56  * This group of variables is used to count calls to the memory
57  * management functions.  Call counting is controlled by the
58  * #MALLOC_CALL_DEBUG symbol, and is off by default.
59  *
60  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink
61  * @ingroup DOXGRP_MEM
62  */
63 
64 /** Count calls to MALLOC().  Count calls to MALLOC(). */
65 static int malloc_count = 0;
66 /** Count calls to CALLOC().  Count calls to CALLOC(). */
67 static int calloc_count = 0;
68 /** Count calls to REALLOC().  Count calls to REALLOC(). */
69 static int realloc_count = 0;
70 /** Count calls to FREE().  Count calls to FREE(). */
71 static int free_count = 0;
72 /*@}*/
73 #endif
74 
75 /**
76  * Allocated pointers.
77  *
78  * This structure keeps track of the pointer array which represents
79  * pointers allocated via the memory management interface.
80  *
81  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, memrec_t_struct
82  * @ingroup DOXGRP_MEM
83  */
84 static memrec_t malloc_rec;
85 /**
86  * Allocated pixmaps.
87  *
88  * This structure keeps track of the pixmap array which represents
89  * pixmaps allocated via the memory management interface.
90  *
91  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, memrec_t_struct
92  * @ingroup DOXGRP_MEM
93  */
94 static memrec_t pixmap_rec;
95 /**
96  * Allocated GC's.
97  *
98  * This structure keeps track of the GC array which represents
99  * X11 Graphics Context objects, or GC's, allocated via the memory
100  * management interface.
101  *
102  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, memrec_t_struct
103  * @ingroup DOXGRP_MEM
104  */
105 static memrec_t gc_rec;
106 
107 /**
108  * Initialize memory management system.
109  *
110  * A call to this function must occur before any other part of the
111  * memory management system is used.  This function initializes the
112  * pointer lists.
113  *
114  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink
115  * @ingroup DOXGRP_MEM
116  */
117 void
spifmem_init(void)118 spifmem_init(void)
119 {
120     D_MEM(("Constructing memory allocation records\n"));
121     malloc_rec.ptrs = (ptr_t *) malloc(sizeof(ptr_t));
122     pixmap_rec.ptrs = (ptr_t *) malloc(sizeof(ptr_t));
123     gc_rec.ptrs = (ptr_t *) malloc(sizeof(ptr_t));
124 }
125 
126 /**
127  * Add a variable to a record set.
128  *
129  * This is the static, internal-use-only function that does the actual
130  * work of recording information on a variable to be tracked.  This
131  * information includes file and line number information and is stored
132  * as a #ptr_t.
133  *
134  * @param memrec   Address of the #memrec_t we're adding to.
135  * @param filename The filename where the variable was allocated.
136  * @param line     The line number of @a filename where the variable
137  *                 was allocated.
138  * @param ptr      The allocated variable.
139  * @param size     The number of bytes requested.
140  *
141  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, MALLOC(), libast_malloc()
142  * @ingroup DOXGRP_MEM
143  */
144 static void
memrec_add_var(memrec_t * memrec,const spif_charptr_t filename,unsigned long line,void * ptr,size_t size)145 memrec_add_var(memrec_t *memrec, const spif_charptr_t filename, unsigned long line, void *ptr, size_t size)
146 {
147     register ptr_t *p;
148 
149     ASSERT(memrec != NULL);
150     memrec->cnt++;
151     if ((memrec->ptrs = (ptr_t *) realloc(memrec->ptrs, sizeof(ptr_t) * memrec->cnt)) == NULL) {
152         D_MEM(("Unable to reallocate pointer list -- %s\n", strerror(errno)));
153     }
154     p = memrec->ptrs + memrec->cnt - 1;
155     D_MEM(("Adding variable (%10p, %lu bytes) from %s:%lu.\n", ptr, size, filename, line));
156     D_MEM(("Storing as pointer #%lu at %10p (from %10p).\n", memrec->cnt, p, memrec->ptrs));
157     p->ptr = ptr;
158     p->size = size;
159     spiftool_safe_strncpy(p->file, SPIF_CONST_CAST(charptr) filename, LIBAST_FNAME_LEN);
160     p->file[LIBAST_FNAME_LEN] = 0;
161     p->line = line;
162 }
163 
164 /**
165  * Find a variable within a record set.
166  *
167  * This function searches through the pointer list of the specified
168  * @a memrec object for a given pointer.
169  *
170  * @param memrec Address of the #memrec_t we're searching.
171  * @param ptr    The value of the requested pointer.
172  * @return       A pointer to the #ptr_t object within @a memrec
173  *               that matches @a ptr, or NULL if not found.
174  *
175  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, MALLOC(), libast_malloc()
176  * @ingroup DOXGRP_MEM
177  */
178 static ptr_t *
memrec_find_var(memrec_t * memrec,const void * ptr)179 memrec_find_var(memrec_t *memrec, const void *ptr)
180 {
181     register ptr_t *p;
182     register unsigned long i;
183 
184     ASSERT_RVAL(memrec != NULL, NULL);
185     REQUIRE_RVAL(ptr != NULL, NULL);
186 
187     for (i = 0, p = memrec->ptrs; i < memrec->cnt; i++, p++) {
188         if (p->ptr == ptr) {
189             D_MEM(("Found pointer #%lu stored at %10p (from %10p)\n", i + 1, p, memrec->ptrs));
190             return p;
191         }
192     }
193     return NULL;
194 }
195 
196 /**
197  * Remove a variable from a record set.
198  *
199  * This is the static, internal-use-only function that does the actual
200  * work of freeing recorded information for a deleted pointer.
201  *
202  * @param memrec   Address of the #memrec_t we're removing from.
203  * @param var      The variable name being freed (for diagnostic
204  *                 purposes only).
205  * @param filename The filename where the variable was freed.
206  * @param line     The line number of @a filename where the variable
207  *                 was freed.
208  * @param ptr      The freed variable.
209  *
210  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, FREE(), libast_free()
211  * @ingroup DOXGRP_MEM
212  */
213 static void
memrec_rem_var(memrec_t * memrec,const spif_charptr_t var,const spif_charptr_t filename,unsigned long line,const void * ptr)214 memrec_rem_var(memrec_t *memrec, const spif_charptr_t var, const spif_charptr_t filename, unsigned long line, const void *ptr)
215 {
216     register ptr_t *p;
217 
218     ASSERT(memrec != NULL);
219     USE_VAR(var);
220     USE_VAR(filename);
221     USE_VAR(line);
222 
223     if ((p = memrec_find_var(memrec, ptr)) == NULL) {
224         D_MEM(("ERROR:  File %s, line %d attempted to free variable %s (%10p) which was not allocated with MALLOC/REALLOC\n",
225                filename, line, var, ptr));
226         return;
227     }
228     D_MEM(("Removing variable %s (%10p) of size %lu\n", var, ptr, p->size));
229     if ((--memrec->cnt) > 0) {
230         memmove(p, p + 1, sizeof(ptr_t) * (memrec->cnt - (p - memrec->ptrs)));
231         memrec->ptrs = (ptr_t *) realloc(memrec->ptrs, sizeof(ptr_t) * memrec->cnt);
232     }
233 }
234 
235 /**
236  * Resize a variable in a record set.
237  *
238  * This is the static, internal-use-only function that does the actual
239  * work of altering information on a tracked variable.
240  *
241  * @param memrec   Address of the #memrec_t we're modifying.
242  * @param var      The variable name being resized (for diagnostic
243  *                 purposes only).
244  * @param filename The filename where the variable was resized.
245  * @param line     The line number of @a filename where the variable
246  *                 was resized.
247  * @param oldp     The old value of the pointer.
248  * @param newp     The new value of the pointer.
249  * @param size     The new size in bytes.
250  *
251  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, REALLOC(), libast_realloc()
252  * @ingroup DOXGRP_MEM
253  */
254 static void
memrec_chg_var(memrec_t * memrec,const spif_charptr_t var,const spif_charptr_t filename,unsigned long line,const void * oldp,void * newp,size_t size)255 memrec_chg_var(memrec_t *memrec, const spif_charptr_t var, const spif_charptr_t filename, unsigned long line, const void *oldp, void *newp, size_t size)
256 {
257     register ptr_t *p;
258 
259     ASSERT(memrec != NULL);
260     USE_VAR(var);
261 
262     if ((p = memrec_find_var(memrec, oldp)) == NULL) {
263         D_MEM(("ERROR:  File %s, line %d attempted to realloc variable %s (%10p) which was not allocated with MALLOC/REALLOC\n", filename,
264                line, var, oldp));
265         return;
266     }
267     D_MEM(("Changing variable %s (%10p, %lu -> %10p, %lu)\n", var, oldp, p->size, newp, size));
268     p->ptr = newp;
269     p->size = size;
270     spiftool_safe_strncpy(p->file, SPIF_CONST_CAST(charptr) filename, LIBAST_FNAME_LEN);
271     p->line = line;
272 }
273 
274 /**
275  * Dump listing of tracked pointers.
276  *
277  * This function dumps a listing of all pointers in @a memrec along
278  * with the filename, line number, address, size, and contents for
279  * each.  Contents are displayed in both hex and ASCII, the latter
280  * having non-printable characters replaced with periods ('.').
281  *
282  * @param memrec Address of the #memrec_t we're dumping.
283  *
284  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, MALLOC_DUMP(), libast_dump_mem_tables()
285  * @ingroup DOXGRP_MEM
286  */
287 static void
memrec_dump_pointers(memrec_t * memrec)288 memrec_dump_pointers(memrec_t *memrec)
289 {
290     register ptr_t *p;
291     unsigned long i, j, k, l, total = 0;
292     unsigned long len;
293     spif_char_t buff[9];
294 
295     ASSERT(memrec != NULL);
296     fprintf(LIBAST_DEBUG_FD, "PTR:  %lu pointers stored.\n", SPIF_CAST_C(unsigned long) memrec->cnt);
297     fprintf(LIBAST_DEBUG_FD,
298             "PTR:   Pointer |       Filename       |  Line  |  Address |  Size  | Offset  | 00 01 02 03 04 05 06 07 |  ASCII  \n");
299     fprintf(LIBAST_DEBUG_FD,
300             "PTR:  ---------+----------------------+--------+----------+--------+---------+-------------------------+---------\n");
301     fflush(LIBAST_DEBUG_FD);
302     len = sizeof(ptr_t) * memrec->cnt;
303     memset(buff, 0, sizeof(buff));
304 
305     /* First, dump the contents of the memrec->ptrs[] array. */
306     for (p = memrec->ptrs, j = 0; j < len; j += 8) {
307         fprintf(LIBAST_DEBUG_FD, "PTR:   %07lu | %20s | %6lu | %10p | %06lu | %07x | ",
308                 (unsigned long) 0, "", (unsigned long) 0,
309                 SPIF_CAST(ptr) memrec->ptrs,
310                 (unsigned long) (sizeof(ptr_t) * memrec->cnt), (unsigned int) j);
311         /* l is the number of characters we're going to output */
312         l = ((len - j < 8) ? (len - j) : (8));
313         /* Copy l bytes (up to 8) from memrec->ptrs[] (p) to buffer */
314         memcpy(buff, ((spif_charptr_t) p) + j, l);
315         buff[l] = 0;
316         for (k = 0; k < l; k++) {
317             fprintf(LIBAST_DEBUG_FD, "%02x ", buff[k]);
318         }
319         /* If we printed less than 8 bytes worth, pad with 3 spaces per byte */
320         for (; k < 8; k++) {
321             fprintf(LIBAST_DEBUG_FD, "   ");
322         }
323         /* Finally, print the printable ASCII string for those l bytes */
324         fprintf(LIBAST_DEBUG_FD, "| %-8s\n", spiftool_safe_str((spif_charptr_t) buff, l));
325         /* Flush after every line in case we crash */
326         fflush(LIBAST_DEBUG_FD);
327     }
328 
329     /* Now print out each pointer and its contents. */
330     for (i = 0; i < memrec->cnt; p++, i++) {
331         /* Add this pointer's size to our total */
332         total += p->size;
333         for (j = 0; j < p->size; j += 8) {
334             fprintf(LIBAST_DEBUG_FD, "PTR:   %07lu | %20s | %6lu | %10p | %06lu | %07x | ",
335                     i + 1, NONULL(p->file), SPIF_CAST_C(unsigned long) p->line,
336                     p->ptr, SPIF_CAST_C(unsigned long) p->size, SPIF_CAST_C(unsigned) j);
337             /* l is the number of characters we're going to output */
338             l = ((p->size - j < 8) ? (p->size - j) : (8));
339             /* Copy l bytes (up to 8) from p->ptr to buffer */
340             memcpy(buff, ((spif_charptr_t) p->ptr) + j, l);
341             buff[l] = 0;
342             for (k = 0; k < l; k++) {
343                 fprintf(LIBAST_DEBUG_FD, "%02x ", buff[k]);
344             }
345             /* If we printed less than 8 bytes worth, pad with 3 spaces per byte */
346             for (; k < 8; k++) {
347                 fprintf(LIBAST_DEBUG_FD, "   ");
348             }
349             /* Finally, print the printable ASCII string for those l bytes */
350             fprintf(LIBAST_DEBUG_FD, "| %-8s\n", spiftool_safe_str(buff, l));
351             /* Flush after every line in case we crash */
352             fflush(LIBAST_DEBUG_FD);
353         }
354     }
355     fprintf(LIBAST_DEBUG_FD, "PTR:  Total allocated memory: %10lu bytes\n", total);
356     fflush(LIBAST_DEBUG_FD);
357 }
358 
359 /**
360  * Dump listing of tracked resources.
361  *
362  * This function is very similar to memrec_dump_pointers() but is
363  * intended for use with non-pointer data.
364  *
365  * @param memrec Address of the #memrec_t we're dumping.
366  *
367  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, MALLOC_DUMP(), libast_dump_mem_tables(),
368  *      memrec_dump_pointers()
369  * @ingroup DOXGRP_MEM
370  */
371 static void
memrec_dump_resources(memrec_t * memrec)372 memrec_dump_resources(memrec_t *memrec)
373 {
374     register ptr_t *p;
375     unsigned long i, total;
376     unsigned long len;
377 
378     ASSERT(memrec != NULL);
379     len = memrec->cnt;
380     fprintf(LIBAST_DEBUG_FD, "RES:  %lu resources stored.\n",
381             SPIF_CAST_C(unsigned long) memrec->cnt);
382     fprintf(LIBAST_DEBUG_FD, "RES:   Index | Resource ID |       Filename       |  Line  |  Size  \n");
383     fprintf(LIBAST_DEBUG_FD, "RES:  -------+-------------+----------------------+--------+--------\n");
384     fflush(LIBAST_DEBUG_FD);
385 
386     for (p = memrec->ptrs, i = 0, total = 0; i < len; i++, p++) {
387         total += p->size;
388         fprintf(LIBAST_DEBUG_FD, "RES:   %5lu |  0x%08lx | %20s | %6lu | %6lu\n",
389                 i, SPIF_CAST_C(unsigned long) p->ptr, NONULL(p->file),
390                 SPIF_CAST_C(unsigned long) p->line,
391                 SPIF_CAST_C(unsigned long) p->size);
392         /* Flush after every line in case we crash */
393         fflush(LIBAST_DEBUG_FD);
394     }
395     fprintf(LIBAST_DEBUG_FD, "RES:  Total size: %lu bytes\n", SPIF_CAST_C(unsigned long) total);
396     fflush(LIBAST_DEBUG_FD);
397 }
398 
399 /******************** MEMORY ALLOCATION INTERFACE ********************/
400 
401 /**
402  * LibAST implementation of malloc().
403  *
404  * When memory debugging is active (via #DEBUG_MEM), all calls to the
405  * MALLOC() macro are routed here.  The macro allows filename and line
406  * number information to be provided thanks to the __FILE__ and
407  * __LINE__ symbols pre-defined by cpp.
408  *
409  * @param filename The filename where the variable is being
410  *                 allocated.
411  * @param line     The line number of @a filename where the variable
412  *                 is being allocated.
413  * @param size     The requested size in bytes (as passed to MALLOC()).
414  * @return         A pointer to the newly-allocated memory.
415  *
416  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, MALLOC()
417  * @ingroup DOXGRP_MEM
418  */
419 void *
spifmem_malloc(const spif_charptr_t filename,unsigned long line,size_t size)420 spifmem_malloc(const spif_charptr_t filename, unsigned long line, size_t size)
421 {
422     void *temp;
423 
424 #if MALLOC_CALL_DEBUG
425     ++malloc_count;
426     if (!(malloc_count % MALLOC_MOD)) {
427         fprintf(LIBAST_DEBUG_FD, "Calls to malloc(): %d\n", malloc_count);
428     }
429 #endif
430 
431     D_MEM(("%lu bytes requested at %s:%lu\n", size, NONULL(filename), line));
432 
433     temp = (void *) malloc(size);
434     ASSERT_RVAL(!SPIF_PTR_ISNULL(temp), SPIF_NULL_TYPE(ptr));
435     if (DEBUG_LEVEL >= DEBUG_MEM) {
436         memrec_add_var(&malloc_rec, SPIF_CAST(charptr) NONULL(filename), line, temp, size);
437     }
438     return (temp);
439 }
440 
441 /**
442  * LibAST implementation of realloc().
443  *
444  * When memory debugging is active (via #DEBUG_MEM), all calls to the
445  * REALLOC() macro are routed here.  The macro allows variable name,
446  * filename, and line number information to be provided.
447  *
448  * @param var      The variable name being resized.
449  * @param filename The filename where the variable is being
450  *                 reallocated.
451  * @param line     The line number of @a filename where the variable
452  *                 is being reallocated.
453  * @param ptr      The old value of the pointer being resized.
454  * @param size     The new requested size in bytes (as passed to
455  *                 REALLOC()).
456  * @return         The new value (possibly moved) of the pointer.
457  *
458  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, REALLOC()
459  * @ingroup DOXGRP_MEM
460  */
461 void *
spifmem_realloc(const spif_charptr_t var,const spif_charptr_t filename,unsigned long line,void * ptr,size_t size)462 spifmem_realloc(const spif_charptr_t var, const spif_charptr_t filename, unsigned long line, void *ptr, size_t size)
463 {
464     void *temp;
465 
466 #if MALLOC_CALL_DEBUG
467     ++realloc_count;
468     if (!(realloc_count % REALLOC_MOD)) {
469         D_MEM(("Calls to realloc(): %d\n", realloc_count));
470     }
471 #endif
472 
473     D_MEM(("Variable %s (%10p -> %lu) at %s:%lu\n", var, ptr, (unsigned long) size, NONULL(filename), line));
474     if (ptr == NULL) {
475         temp = (void *) spifmem_malloc(filename, line, size);
476     } else if (size == 0) {
477         spifmem_free(var, filename, line, ptr);
478         temp = NULL;
479     } else {
480         temp = (void *) realloc(ptr, size);
481         ASSERT_RVAL(!SPIF_PTR_ISNULL(temp), SPIF_NULL_TYPE(ptr));
482         if (DEBUG_LEVEL >= DEBUG_MEM) {
483             memrec_chg_var(&malloc_rec, var, SPIF_CAST(charptr) NONULL(filename), line, ptr, temp, size);
484         }
485     }
486     return (temp);
487 }
488 
489 /**
490  * LibAST implementation of calloc().
491  *
492  * When memory debugging is active (via #DEBUG_MEM), all calls to the
493  * CALLOC() macro are routed here.  The macro allows filename and line
494  * number information to be provided thanks to the __FILE__ and
495  * __LINE__ symbols pre-defined by cpp.
496  *
497  * @param filename The filename where the variable is being
498  *                 allocated.
499  * @param line     The line number of @a filename where the variable
500  *                 is being allocated.
501  * @param count    The number of objects being allocated.
502  * @param size     The size in bytes of each object (as passed to
503  *                 CALLOC()).
504  * @return         A pointer to the newly-allocated, zeroed memory.
505  *
506  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, CALLOC()
507  * @ingroup DOXGRP_MEM
508  */
509 void *
spifmem_calloc(const spif_charptr_t filename,unsigned long line,size_t count,size_t size)510 spifmem_calloc(const spif_charptr_t filename, unsigned long line, size_t count, size_t size)
511 {
512     void *temp;
513 
514 #if MALLOC_CALL_DEBUG
515     ++calloc_count;
516     if (!(calloc_count % CALLOC_MOD)) {
517         fprintf(LIBAST_DEBUG_FD, "Calls to calloc(): %d\n", calloc_count);
518     }
519 #endif
520 
521     D_MEM(("%lu units of %lu bytes each requested at %s:%lu\n", count, size, NONULL(filename), line));
522     temp = (void *) calloc(count, size);
523     ASSERT_RVAL(!SPIF_PTR_ISNULL(temp), SPIF_NULL_TYPE(ptr));
524     if (DEBUG_LEVEL >= DEBUG_MEM) {
525         memrec_add_var(&malloc_rec, SPIF_CAST(charptr) NONULL(filename), line, temp, size * count);
526     }
527     return (temp);
528 }
529 
530 /**
531  * LibAST implementation of free().
532  *
533  * When memory debugging is active (via #DEBUG_MEM), all calls to the
534  * FREE() macro are routed here.  The macro allows variable name,
535  * filename, and line number information to be provided.
536  *
537  * @param var      The variable name being freed.
538  * @param filename The filename where the variable is being freed.
539  * @param line     The line number of @a filename where the variable
540  *                 is being freed.
541  * @param ptr      The pointer being freed (as passed to FREE()).
542  *
543  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, FREE()
544  * @ingroup DOXGRP_MEM
545  */
546 void
spifmem_free(const spif_charptr_t var,const spif_charptr_t filename,unsigned long line,void * ptr)547 spifmem_free(const spif_charptr_t var, const spif_charptr_t filename, unsigned long line, void *ptr)
548 {
549 #if MALLOC_CALL_DEBUG
550     ++free_count;
551     if (!(free_count % FREE_MOD)) {
552         fprintf(LIBAST_DEBUG_FD, "Calls to free(): %d\n", free_count);
553     }
554 #endif
555 
556     D_MEM(("Variable %s (%10p) at %s:%lu\n", var, ptr, NONULL(filename), line));
557     if (ptr) {
558         if (DEBUG_LEVEL >= DEBUG_MEM) {
559             memrec_rem_var(&malloc_rec, var, SPIF_CAST(charptr) NONULL(filename), line, ptr);
560         }
561         free(ptr);
562     } else {
563         D_MEM(("ERROR:  Caught attempt to free NULL pointer\n"));
564     }
565 }
566 
567 /**
568  * LibAST implementation of strdup().
569  *
570  * When memory debugging is active (via #DEBUG_MEM), all calls to the
571  * STRDUP() macro are routed here.  The macro allows variable name,
572  * filename, and line number information to be provided.
573  *
574  * @param var      The variable name being duplicated.
575  * @param filename The filename where the variable is being duplicated.
576  * @param line     The line number of @a filename where the variable
577  *                 is being duplicated.
578  * @param str      The string being duplicated (as passed to STRDUP()).
579  * @return         A pointer to a newly-allocated copy of @a str.
580  *
581  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, STRDUP()
582  * @ingroup DOXGRP_MEM
583  */
584 spif_charptr_t
spifmem_strdup(const spif_charptr_t var,const spif_charptr_t filename,unsigned long line,const spif_charptr_t str)585 spifmem_strdup(const spif_charptr_t var, const spif_charptr_t filename, unsigned long line, const spif_charptr_t str)
586 {
587     register spif_charptr_t newstr;
588     register size_t len;
589 
590     ASSERT_RVAL(!SPIF_PTR_ISNULL(str), SPIF_NULL_TYPE_C(spif_charptr_t));
591     USE_VAR(var);
592     D_MEM(("Variable %s (%10p) at %s:%lu\n", var, str, NONULL(filename), line));
593 
594     len = strlen(SPIF_CAST_C(char *) str) + 1;      /* Copy NUL byte also */
595     newstr = SPIF_CAST(charptr) spifmem_malloc(SPIF_CAST(charptr) NONULL(filename), line, len);
596     ASSERT_RVAL(!SPIF_PTR_ISNULL(newstr), SPIF_NULL_TYPE(ptr));
597     strcpy(SPIF_CAST_C(char *) newstr, SPIF_CAST_C(char *) str);
598     return (newstr);
599 }
600 
601 /**
602  * Dump listing of tracked pointers.
603  *
604  * This function simply calls memrec_dump_pointers() and passes in the
605  * address of the #malloc_rec variable.
606  *
607  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, MALLOC_DUMP(), memrec_dump_pointers()
608  * @ingroup DOXGRP_MEM
609  */
610 void
spifmem_dump_mem_tables(void)611 spifmem_dump_mem_tables(void)
612 {
613     fprintf(LIBAST_DEBUG_FD, "Dumping memory allocation table:\n");
614     memrec_dump_pointers(&malloc_rec);
615 }
616 
617 #if LIBAST_X11_SUPPORT
618 
619 /******************** PIXMAP ALLOCATION INTERFACE ********************/
620 
621 /**
622  * LibAST implementation of XCreatePixmap().
623  *
624  * When memory debugging is active (via #DEBUG_MEM), all calls to the
625  * X_CREATE_PIXMAP() macro are routed here.  The macro allows filename
626  * and line number information to be provided thanks to the __FILE__
627  * and __LINE__ symbols pre-defined by cpp.
628  *
629  * @param filename The filename where the pixmap is being created.
630  * @param line     The line number of @a filename where the pixmap is
631  *                 being created.
632  * @param d        The Display for the new pixmap.
633  * @param win      The Drawable for the new pixmap.
634  * @param w        Width of the pixmap, in pixels.
635  * @param h        Height of the pixmap, in pixels.
636  * @param depth    The color depth for the new pixmap.
637  * @return         A newly-created Pixmap.
638  *
639  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, X_CREATE_PIXMAP()
640  * @ingroup DOXGRP_MEM
641  */
642 Pixmap
spifmem_x_create_pixmap(const spif_charptr_t filename,unsigned long line,Display * d,Drawable win,unsigned int w,unsigned int h,unsigned int depth)643 spifmem_x_create_pixmap(const spif_charptr_t filename, unsigned long line, Display * d, Drawable win, unsigned int w, unsigned int h,
644                        unsigned int depth)
645 {
646     Pixmap p;
647 
648     p = XCreatePixmap(d, win, w, h, depth);
649     D_MEM(("Created %ux%u pixmap 0x%08x of depth %u for window 0x%08x at %s:%lu\n", w, h, p, depth, win, NONULL(filename), line));
650     ASSERT_RVAL(p != None, None);
651     if (DEBUG_LEVEL >= DEBUG_MEM) {
652         memrec_add_var(&pixmap_rec, SPIF_CAST(charptr) NONULL(filename), line, (void *) p, w * h * (depth / 8));
653     }
654     return (p);
655 }
656 
657 /**
658  * LibAST implementation of XFreePixmap().
659  *
660  * When memory debugging is active (via #DEBUG_MEM), all calls to the
661  * X_FREE_PIXMAP() macro are routed here.  The macro allows variable
662  * name, filename, and line number information to be provided.
663  *
664  * @param var      The variable name of the pixmap being freed.
665  * @param filename The filename where the pixmap is being freed.
666  * @param line     The line number of @a filename where the pixmap is
667  *                 being freed.
668  * @param d        The Display for the pixmap.
669  * @param p        The Pixmap to be freed.
670  *
671  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, X_FREE_PIXMAP()
672  * @ingroup DOXGRP_MEM
673  */
674 void
spifmem_x_free_pixmap(const spif_charptr_t var,const spif_charptr_t filename,unsigned long line,Display * d,Pixmap p)675 spifmem_x_free_pixmap(const spif_charptr_t var, const spif_charptr_t filename, unsigned long line, Display * d, Pixmap p)
676 {
677     D_MEM(("Freeing pixmap %s (0x%08x) at %s:%lu\n", var, p, NONULL(filename), line));
678     if (p) {
679         if (DEBUG_LEVEL >= DEBUG_MEM) {
680             memrec_rem_var(&pixmap_rec, var, SPIF_CAST(charptr) NONULL(filename), line, (void *) p);
681         }
682         XFreePixmap(d, p);
683     } else {
684         D_MEM(("ERROR:  Caught attempt to free NULL pixmap\n"));
685     }
686 }
687 
688 # if LIBAST_IMLIB2_SUPPORT
689 /**
690  * Register a pixmap for tracking.
691  *
692  * Imlib has its own mechanism for creating pixmaps internally.  In
693  * order to keep track of these pixmaps, they must be registered with
694  * LibAST using this function (via the IMLIB_REGISTER_PIXMAP() macro).
695  *
696  * @param var      The variable name of the pixmap being registered.
697  * @param filename The filename where the pixmap is being registered.
698  * @param line     The line number of @a filename where the pixmap is
699  *                 being registered.
700  * @param p        The Pixmap being registered.
701  *
702  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, IMLIB_REGISTER_PIXMAP()
703  * @ingroup DOXGRP_MEM
704  */
705 void
spifmem_imlib_register_pixmap(const spif_charptr_t var,const spif_charptr_t filename,unsigned long line,Pixmap p)706 spifmem_imlib_register_pixmap(const spif_charptr_t var, const spif_charptr_t filename, unsigned long line, Pixmap p)
707 {
708     USE_VAR(var);
709     D_MEM(("Registering pixmap %s (0x%08x) created by Imlib2 at %s:%lu\n", var, p, NONULL(filename), line));
710     if (p) {
711         if (DEBUG_LEVEL >= DEBUG_MEM) {
712             if (!memrec_find_var(&pixmap_rec, (void *) p)) {
713                 memrec_add_var(&pixmap_rec, SPIF_CAST(charptr) NONULL(filename), line, (void *) p, 1);
714             } else {
715                 D_MEM(("Pixmap 0x%08x already registered.\n"));
716             }
717         }
718     } else {
719         D_MEM(("ERROR:  Refusing to register a NULL pixmap\n"));
720     }
721 }
722 
723 /**
724  * Free a pixmap created by Imlib.
725  *
726  * Imlib has its own mechanism for freeing pixmaps, and their
727  * associated mask (if any), internally.  All pixmaps created by Imlib
728  * must also be freed by Imlib.  It is safe, albeit a bit slower, to
729  * free all pixmaps via Imlib, regardless of how they were created.
730  *
731  * @param var      The variable name of the pixmap being freed.
732  * @param filename The filename where the pixmap is being freed.
733  * @param line     The line number of @a filename where the pixmap is
734  *                 being freed.
735  * @param p        The Pixmap being freed.
736  *
737  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, IMLIB_FREE_PIXMAP()
738  * @ingroup DOXGRP_MEM
739  */
740 void
spifmem_imlib_free_pixmap(const spif_charptr_t var,const spif_charptr_t filename,unsigned long line,Pixmap p)741 spifmem_imlib_free_pixmap(const spif_charptr_t var, const spif_charptr_t filename, unsigned long line, Pixmap p)
742 {
743     D_MEM(("Freeing pixmap %s (0x%08x) at %s:%lu using Imlib2\n", var, p, NONULL(filename), line));
744     if (p) {
745         if (DEBUG_LEVEL >= DEBUG_MEM) {
746             memrec_rem_var(&pixmap_rec, var, SPIF_CAST(charptr) NONULL(filename), line, (void *) p);
747         }
748         imlib_free_pixmap_and_mask(p);
749     } else {
750         D_MEM(("ERROR:  Caught attempt to free NULL pixmap\n"));
751     }
752 }
753 # endif
754 
755 /**
756  * Dump listing of tracked pixmaps.
757  *
758  * This function simply calls memrec_dump_resources() and passes in
759  * the address of the #pixmap_rec variable.
760  *
761  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, PIXMAP_DUMP(), memrec_dump_resources()
762  * @ingroup DOXGRP_MEM
763  */
764 void
spifmem_dump_pixmap_tables(void)765 spifmem_dump_pixmap_tables(void)
766 {
767     fprintf(LIBAST_DEBUG_FD, "Dumping X11 Pixmap allocation table:\n");
768     memrec_dump_resources(&pixmap_rec);
769 }
770 
771 
772 
773 /********************** GC ALLOCATION INTERFACE **********************/
774 
775 /**
776  * LibAST implementation of XCreateGC().
777  *
778  * When memory debugging is active (via #DEBUG_MEM), all calls to the
779  * X_CREATE_GC() macro are routed here.  The macro allows filename
780  * and line number information to be provided thanks to the __FILE__
781  * and __LINE__ symbols pre-defined by cpp.
782  *
783  * @param filename The filename where the GC is being created.
784  * @param line     The line number of @a filename where the GC is
785  *                 being created.
786  * @param d        The Display for the new GC.
787  * @param win      The Drawable for the new GC.
788  * @param mask     Bitwise OR of zero or more GC flags.
789  * @param gcv      Pointer to XGCValues structure.
790  * @return         A newly-created GC.
791  *
792  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, X_CREATE_GC()
793  * @ingroup DOXGRP_MEM
794  */
795 GC
spifmem_x_create_gc(const spif_charptr_t filename,unsigned long line,Display * d,Drawable win,unsigned long mask,XGCValues * gcv)796 spifmem_x_create_gc(const spif_charptr_t filename, unsigned long line, Display * d, Drawable win, unsigned long mask, XGCValues * gcv)
797 {
798     GC gc;
799 
800     D_MEM(("Creating gc for window 0x%08x at %s:%lu\n", win, NONULL(filename), line));
801 
802     gc = XCreateGC(d, win, mask, gcv);
803     ASSERT_RVAL(gc != None, None);
804     if (DEBUG_LEVEL >= DEBUG_MEM) {
805         memrec_add_var(&gc_rec, SPIF_CAST(charptr) NONULL(filename), line, (void *) gc, sizeof(XGCValues));
806     }
807     return (gc);
808 }
809 
810 /**
811  * LibAST implementation of XFreeGC().
812  *
813  * When memory debugging is active (via #DEBUG_MEM), all calls to the
814  * X_FREE_GC() macro are routed here.  The macro allows variable
815  * name, filename, and line number information to be provided.
816  *
817  * @param var      The variable name of the GC being freed.
818  * @param filename The filename where the GC is being freed.
819  * @param line     The line number of @a filename where the GC is
820  *                 being freed.
821  * @param d        The Display for the GC.
822  * @param gc       The GC to be freed.
823  *
824  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, X_FREE_GC()
825  * @ingroup DOXGRP_MEM
826  */
827 void
spifmem_x_free_gc(const spif_charptr_t var,const spif_charptr_t filename,unsigned long line,Display * d,GC gc)828 spifmem_x_free_gc(const spif_charptr_t var, const spif_charptr_t filename, unsigned long line, Display * d, GC gc)
829 {
830     D_MEM(("spifmem_x_free_gc() called for variable %s (0x%08x) at %s:%lu\n", var, gc, NONULL(filename), line));
831     if (gc) {
832         if (DEBUG_LEVEL >= DEBUG_MEM) {
833             memrec_rem_var(&gc_rec, var, SPIF_CAST(charptr) NONULL(filename), line, (void *) gc);
834         }
835         XFreeGC(d, gc);
836     } else {
837         D_MEM(("ERROR:  Caught attempt to free NULL GC\n"));
838     }
839 }
840 
841 /**
842  * Dump listing of tracked GC's.
843  *
844  * This function simply calls memrec_dump_resources() and passes in
845  * the address of the #gc_rec variable.
846  *
847  * @see @link DOXGRP_MEM Memory Management Subsystem @endlink, GC_DUMP(), memrec_dump_resources()
848  * @ingroup DOXGRP_MEM
849  */
850 void
spifmem_dump_gc_tables(void)851 spifmem_dump_gc_tables(void)
852 {
853     fprintf(LIBAST_DEBUG_FD, "Dumping X11 GC allocation table:\n");
854     memrec_dump_resources(&gc_rec);
855 }
856 #endif
857 
858 /**
859  * Free an array of pointers.
860  *
861  * This really doesn't relate to the memory management subsystem, per
862  * se.  It is simply a convenience function which simplifies the
863  * freeing of pointer arrays.  The first @a count pointers in the
864  * array are freed, after which the array itself is freed.  If
865  * @a count is 0, the array must be NULL-terminated.  All pointers up
866  * to the first NULL pointer encountered will be freed.
867  *
868  * @param list  The pointer array to be freed.  This variable's value
869  *              MUST NOT be used after being passed to this function.
870  * @param count The number of pointers in the array, or 0 for a
871  *              NULL-terminated array.
872  *
873  * @ingroup DOXGRP_MEM
874  */
875 void
spiftool_free_array(void * list,size_t count)876 spiftool_free_array(void *list, size_t count)
877 {
878     register size_t i;
879     void **l = (void **) list;
880 
881     REQUIRE(list != NULL);
882 
883     if (count == 0) {
884         count = (size_t) (-1);
885     }
886     for (i = 0; i < count && l[i]; i++) {
887         FREE(l[i]);
888     }
889     FREE(list);
890 }
891 
892 /**
893  * @defgroup DOXGRP_MEM Memory Management Subsystem
894  *
895  * This group of functions/defines/macros implements the memory
896  * management subsystem within LibAST.
897  *
898  * LibAST provides a robust mechanism for tracking memory allocations
899  * and deallocations.  This system employs macro-based wrappers
900  * around the standard libc malloc/realloc/calloc/free routines, other
901  * libc fare such as strdup(), Xlib GC and Pixmap create/free
902  * routines, and even Imlib2's own pixmap functions.
903  *
904  * To take advantage of this system, simply substitute the macro
905  * versions in place of the standard versions throughout your code
906  * (e.g., use MALLOC() instead of malloc(), X_FREE_GC() instead of
907  * XFreeGC(), etc.).  If DEBUG is set to a value higher than
908  * DEBUG_MEM, the LibAST-custom versions of these functions will be
909  * used.  Of course, if memory debugging has not been requested, the
910  * original libc/XLib/Imlib2 versions will be used instead, so that
911  * you only incur the debugging overhead when you want it.
912  *
913  * LibAST has also been designed to work effectively with Gray
914  * Watson's excellent malloc-debugging library, dmalloc
915  * (http://dmalloc.com/), either instead of or in addition to its own
916  * memory tracking routines.  Unlike LibAST, dmalloc supplements
917  * memory allocation tracking with fence-post checking, freed pointer
918  * reuse detection, and other very handy features.
919  *
920  * A small sample program demonstrating use of LibAST's memory
921  * management system can be found
922  * @link mem_example.c here @endlink.
923  */
924 
925 /**
926  * @example mem_example.c
927  * Example code for using the memory management subsystem.
928  *
929  * This small program demonstrates how to use LibAST's built-in memory
930  * management system as well as a few of the errors it can catch for
931  * you.
932  *
933  * The following shows output similar to what you can expect to
934  * receive if you build and run this program:
935  *
936  * @code
937  * $ ./mem_example
938  * [1045859036]        mem.c |  246: spifmem_malloc(): 500 bytes requested at mem_example.c:27
939  * [1045859036]        mem.c |   74: memrec_add_var(): Adding variable (0x8049a20, 500 bytes) from mem_example.c:27.
940  * [1045859036]        mem.c |   75: memrec_add_var(): Storing as pointer #1 at 0x8049c18 (from 0x8049c18).
941  * [1045859036]        mem.c |  329: spifmem_strdup(): Variable pointer (0x8049a20) at mem_example.c:36
942  * [1045859036]        mem.c |  246: spifmem_malloc(): 16 bytes requested at mem_example.c:36
943  * [1045859036]        mem.c |   74: memrec_add_var(): Adding variable (0x8049c40, 16 bytes) from mem_example.c:36.
944  * [1045859036]        mem.c |   75: memrec_add_var(): Storing as pointer #2 at 0x8049c7c (from 0x8049c58).
945  * [1045859036]        mem.c |  312: spifmem_free(): Variable dup (0x8049c40) at mem_example.c:39
946  * [1045859036]        mem.c |   94: memrec_find_var(): Found pointer #2 stored at 0x8049c7c (from 0x8049c58)
947  * [1045859036]        mem.c |  113: memrec_rem_var(): Removing variable dup (0x8049c40) of size 16
948  * [1045859036]        mem.c |  312: spifmem_free(): Variable dup (   (nil)) at mem_example.c:43
949  * [1045859036]        mem.c |  319: spifmem_free(): ERROR:  Caught attempt to free NULL pointer
950  * [1045859036]        mem.c |  268: spifmem_realloc(): Variable pointer (0x8049a20 -> 1000) at mem_example.c:46
951  * [1045859036]        mem.c |   94: memrec_find_var(): Found pointer #1 stored at 0x8049c58 (from 0x8049c58)
952  * [1045859036]        mem.c |  132: memrec_chg_var(): Changing variable pointer (0x8049a20, 500 -> 0x8049c80, 1000)
953  * Dumping memory allocation table:
954  * PTR:  1 pointers stored.
955  * PTR:   Pointer |       Filename       |  Line  |  Address |  Size  | Offset  | 00 01 02 03 04 05 06 07 |  ASCII
956  * PTR:  ---------+----------------------+--------+----------+--------+---------+-------------------------+---------
957  * PTR:   0000000 |                      |      0 | 0x8049c58 | 000036 | 0000000 | 80 9c 04 08 e8 03 00 00 | ��..�...
958  * PTR:   0000000 |                      |      0 | 0x8049c58 | 000036 | 0000008 | 6d 65 6d 5f 65 78 61 6d | mem_exam
959  * PTR:   0000000 |                      |      0 | 0x8049c58 | 000036 | 0000010 | 70 6c 65 2e 63 00 00 00 | ple.c...
960  * PTR:   0000000 |                      |      0 | 0x8049c58 | 000036 | 0000018 | 00 00 00 00 00 00 00 00 | ........
961  * PTR:   0000000 |                      |      0 | 0x8049c58 | 000036 | 0000020 | 2e 00 00 00             | ....
962  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000000 | 54 68 69 73 20 69 73 20 | This is
963  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000008 | 61 20 74 65 73 74 2e 00 | a test..
964  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000010 | 00 00 00 00 00 00 00 00 | ........
965  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000018 | 00 00 00 00 00 00 00 00 | ........
966  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000020 | 00 00 00 00 00 00 00 00 | ........
967  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000028 | 00 00 00 00 00 00 00 00 | ........
968  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000030 | 00 00 00 00 00 00 00 00 | ........
969  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000038 | 00 00 00 00 00 00 00 00 | ........
970  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000040 | 00 00 00 00 00 00 00 00 | ........
971  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000048 | 00 00 00 00 00 00 00 00 | ........
972  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000050 | 00 00 00 00 00 00 00 00 | ........
973  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000058 | 00 00 00 00 00 00 00 00 | ........
974  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000060 | 00 00 00 00 00 00 00 00 | ........
975  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000068 | 00 00 00 00 00 00 00 00 | ........
976  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000070 | 00 00 00 00 00 00 00 00 | ........
977  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000078 | 00 00 00 00 00 00 00 00 | ........
978  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000080 | 00 00 00 00 00 00 00 00 | ........
979  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000088 | 00 00 00 00 00 00 00 00 | ........
980  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000090 | 00 00 00 00 00 00 00 00 | ........
981  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000098 | 00 00 00 00 00 00 00 00 | ........
982  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000a0 | 00 00 00 00 00 00 00 00 | ........
983  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000a8 | 00 00 00 00 00 00 00 00 | ........
984  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000b0 | 00 00 00 00 00 00 00 00 | ........
985  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000b8 | 00 00 00 00 00 00 00 00 | ........
986  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000c0 | 00 00 00 00 00 00 00 00 | ........
987  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000c8 | 00 00 00 00 00 00 00 00 | ........
988  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000d0 | 00 00 00 00 00 00 00 00 | ........
989  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000d8 | 00 00 00 00 00 00 00 00 | ........
990  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000e0 | 00 00 00 00 00 00 00 00 | ........
991  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000e8 | 00 00 00 00 00 00 00 00 | ........
992  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000f0 | 00 00 00 00 00 00 00 00 | ........
993  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00000f8 | 00 00 00 00 00 00 00 00 | ........
994  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000100 | 00 00 00 00 00 00 00 00 | ........
995  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000108 | 00 00 00 00 00 00 00 00 | ........
996  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000110 | 00 00 00 00 00 00 00 00 | ........
997  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000118 | 00 00 00 00 00 00 00 00 | ........
998  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000120 | 00 00 00 00 00 00 00 00 | ........
999  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000128 | 00 00 00 00 00 00 00 00 | ........
1000  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000130 | 00 00 00 00 00 00 00 00 | ........
1001  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000138 | 00 00 00 00 00 00 00 00 | ........
1002  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000140 | 00 00 00 00 00 00 00 00 | ........
1003  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000148 | 00 00 00 00 00 00 00 00 | ........
1004  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000150 | 00 00 00 00 00 00 00 00 | ........
1005  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000158 | 00 00 00 00 00 00 00 00 | ........
1006  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000160 | 00 00 00 00 00 00 00 00 | ........
1007  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000168 | 00 00 00 00 00 00 00 00 | ........
1008  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000170 | 00 00 00 00 00 00 00 00 | ........
1009  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000178 | 00 00 00 00 00 00 00 00 | ........
1010  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000180 | 00 00 00 00 00 00 00 00 | ........
1011  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000188 | 00 00 00 00 00 00 00 00 | ........
1012  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000190 | 00 00 00 00 00 00 00 00 | ........
1013  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000198 | 00 00 00 00 00 00 00 00 | ........
1014  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001a0 | 00 00 00 00 00 00 00 00 | ........
1015  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001a8 | 00 00 00 00 00 00 00 00 | ........
1016  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001b0 | 00 00 00 00 00 00 00 00 | ........
1017  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001b8 | 00 00 00 00 00 00 00 00 | ........
1018  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001c0 | 00 00 00 00 00 00 00 00 | ........
1019  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001c8 | 00 00 00 00 00 00 00 00 | ........
1020  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001d0 | 00 00 00 00 00 00 00 00 | ........
1021  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001d8 | 00 00 00 00 00 00 00 00 | ........
1022  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001e0 | 00 00 00 00 00 00 00 00 | ........
1023  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001e8 | 00 00 00 00 00 00 00 00 | ........
1024  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001f0 | 00 00 00 00 00 00 00 00 | ........
1025  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00001f8 | 00 00 00 00 00 00 00 00 | ........
1026  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000200 | 00 00 00 00 00 00 00 00 | ........
1027  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000208 | 00 00 00 00 00 00 00 00 | ........
1028  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000210 | 00 00 00 00 00 00 00 00 | ........
1029  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000218 | 00 00 00 00 00 00 00 00 | ........
1030  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000220 | 00 00 00 00 00 00 00 00 | ........
1031  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000228 | 00 00 00 00 00 00 00 00 | ........
1032  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000230 | 00 00 00 00 00 00 00 00 | ........
1033  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000238 | 00 00 00 00 00 00 00 00 | ........
1034  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000240 | 00 00 00 00 00 00 00 00 | ........
1035  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000248 | 00 00 00 00 00 00 00 00 | ........
1036  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000250 | 00 00 00 00 00 00 00 00 | ........
1037  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000258 | 00 00 00 00 00 00 00 00 | ........
1038  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000260 | 00 00 00 00 00 00 00 00 | ........
1039  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000268 | 00 00 00 00 00 00 00 00 | ........
1040  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000270 | 00 00 00 00 00 00 00 00 | ........
1041  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000278 | 00 00 00 00 00 00 00 00 | ........
1042  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000280 | 00 00 00 00 00 00 00 00 | ........
1043  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000288 | 00 00 00 00 00 00 00 00 | ........
1044  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000290 | 00 00 00 00 00 00 00 00 | ........
1045  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000298 | 00 00 00 00 00 00 00 00 | ........
1046  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002a0 | 00 00 00 00 00 00 00 00 | ........
1047  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002a8 | 00 00 00 00 00 00 00 00 | ........
1048  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002b0 | 00 00 00 00 00 00 00 00 | ........
1049  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002b8 | 00 00 00 00 00 00 00 00 | ........
1050  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002c0 | 00 00 00 00 00 00 00 00 | ........
1051  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002c8 | 00 00 00 00 00 00 00 00 | ........
1052  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002d0 | 00 00 00 00 00 00 00 00 | ........
1053  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002d8 | 00 00 00 00 00 00 00 00 | ........
1054  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002e0 | 00 00 00 00 00 00 00 00 | ........
1055  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002e8 | 00 00 00 00 00 00 00 00 | ........
1056  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002f0 | 00 00 00 00 00 00 00 00 | ........
1057  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00002f8 | 00 00 00 00 00 00 00 00 | ........
1058  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000300 | 00 00 00 00 00 00 00 00 | ........
1059  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000308 | 00 00 00 00 00 00 00 00 | ........
1060  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000310 | 00 00 00 00 00 00 00 00 | ........
1061  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000318 | 00 00 00 00 00 00 00 00 | ........
1062  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000320 | 00 00 00 00 00 00 00 00 | ........
1063  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000328 | 00 00 00 00 00 00 00 00 | ........
1064  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000330 | 00 00 00 00 00 00 00 00 | ........
1065  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000338 | 00 00 00 00 00 00 00 00 | ........
1066  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000340 | 00 00 00 00 00 00 00 00 | ........
1067  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000348 | 00 00 00 00 00 00 00 00 | ........
1068  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000350 | 00 00 00 00 00 00 00 00 | ........
1069  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000358 | 00 00 00 00 00 00 00 00 | ........
1070  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000360 | 00 00 00 00 00 00 00 00 | ........
1071  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000368 | 00 00 00 00 00 00 00 00 | ........
1072  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000370 | 00 00 00 00 00 00 00 00 | ........
1073  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000378 | 00 00 00 00 00 00 00 00 | ........
1074  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000380 | 00 00 00 00 00 00 00 00 | ........
1075  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000388 | 00 00 00 00 00 00 00 00 | ........
1076  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000390 | 00 00 00 00 00 00 00 00 | ........
1077  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 0000398 | 00 00 00 00 00 00 00 00 | ........
1078  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00003a0 | 00 00 00 00 00 00 00 00 | ........
1079  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00003a8 | 00 00 00 00 00 00 00 00 | ........
1080  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00003b0 | 00 00 00 00 00 00 00 00 | ........
1081  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00003b8 | 00 00 00 00 00 00 00 00 | ........
1082  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00003c0 | 00 00 00 00 00 00 00 00 | ........
1083  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00003c8 | 00 00 00 00 00 00 00 00 | ........
1084  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00003d0 | 00 00 00 00 00 00 00 00 | ........
1085  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00003d8 | 00 00 00 00 00 00 00 00 | ........
1086  * PTR:   0000001 |        mem_example.c |     46 | 0x8049c80 | 001000 | 00003e0 | 00 00 00 00 00 00 00 00 | ........
1087  * PTR:  Total allocated memory:       1000 bytes
1088  * @endcode
1089  *
1090  * Here is the source code:
1091  */
1092