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