1 /*
2 * Copyright (C) 2001 Andrew Ferguson <andrew@owsla.cjb.net>
3 * Copyright (C) 2001 Sasha Vasko <sasha at aftercode.net>
4 * Copyright (C) 1999 Ethan Fischer <allanon@crystaltokyo.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <string.h> /* for memset */
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <sys/types.h>
26 #include <signal.h>
27
28 #include "config.h"
29
30 #include "astypes.h"
31 #include "output.h"
32 #include "ashash.h"
33 #include "audit.h"
34 #include "selfdiag.h"
35
36 #ifdef DEBUG_ALLOCS
37
38 #undef malloc
39 #undef safemalloc
40 #undef calloc
41 #undef realloc
42 #undef add_hash_item
43 #undef free
44 #undef mystrdup
45 #undef mystrndup
46
47 #ifndef X_DISPLAY_MISSING
48
49 #undef XCreatePixmap
50 #undef XCreateBitmapFromData
51 #undef XCreatePixmapFromBitmapData
52 #undef XFreePixmap
53
54 #undef XCreateGC
55 #undef XFreeGC
56
57 #undef XCreateImage
58 #undef XGetImage
59 #undef XSubImage
60 #undef XDestroyImage
61
62 #undef XGetWindowProperty
63 #undef XListProperties
64 #undef XGetTextProperty
65 #undef XAllocClassHint
66 #undef XAllocSizeHints
67 #undef XQueryTree
68 #undef XGetWMHints
69 #undef XGetWMProtocols
70 #undef XGetWMName
71 #undef XGetClassHint
72 #undef XGetAtomName
73 #undef XStringListToTextProperty
74 #undef XFree
75
76 #endif /* #ifndef X_DISPLAY_MISSING */
77 #endif /* DEBUG_ALLOCS */
78
79 #include "mystring.h"
80 #include "safemalloc.h"
81
82 int
as_assert(void * p,const char * fname,int line,const char * call)83 as_assert (void *p, const char *fname, int line, const char *call)
84 {
85 if (p == NULL)
86 fprintf (stderr, "ASSERT FAILED: NULL pointer in %s, line# %d (%s())\n", fname, line, call);
87 return (p == NULL);
88 }
89
90 #define MAX_AUDIT_ALLOCS 30000
91
92 typedef struct mem
93 {
94 void *ptr;
95 const char *fname;
96 size_t length;
97 short int type;
98 short int line;
99 char freed;
100 }
101 mem;
102
103 enum
104 {
105 C_MEM = 0,
106 C_MALLOC = 0x100,
107 C_CALLOC = 0x200,
108 C_REALLOC = 0x300,
109 C_ADD_HASH_ITEM = 0x400,
110 C_MYSTRDUP = 0x500,
111 C_MYSTRNDUP = 0x600,
112
113 C_PIXMAP = 1,
114 C_CREATEPIXMAP = 0x100,
115 C_BITMAPFROMDATA = 0x200,
116 C_FROMBITMAP = 0x300,
117
118 C_GC = 2,
119
120 C_IMAGE = 3,
121 C_GETIMAGE = 0x100,
122 /* C_XPMFILE = 0x200, *//* must be same as pixmap version above */
123 C_SUBIMAGE = 0x300,
124
125 C_XMEM = 4,
126 C_XGETWINDOWPROPERTY = 0x100,
127 C_XLISTPROPERTIES = 0x200,
128 C_XGETTEXTPROPERTY = 0x300,
129 C_XALLOCCLASSHINT = 0x400,
130 C_XALLOCSIZEHINTS = 0x500,
131 C_XQUERYTREE = 0x600,
132 C_XGETWMHINTS = 0x700,
133 C_XGETWMPROTOCOLS = 0x800,
134 C_XGETWMNAME = 0x900,
135 C_XGETCLASSHINT = 0xa00,
136 C_XGETATOMNAME = 0xb00,
137 C_XSTRINGLISTTOTEXTPROPERTY = 0xc00,
138
139 C_LAST_TYPE
140 };
141
142 static ASHashTable *allocs_hash = NULL ;
143
144 #define DEALLOC_CACHE_SIZE 128
145 static mem* deallocated_mem[DEALLOC_CACHE_SIZE+10] ;
146 static unsigned int deallocated_used = 0 ;
147
148 static long allocations = 0;
149 static long reallocations = 0;
150 static long deallocations = 0;
151 static long max_allocations = 0;
152 static unsigned long max_alloc = 0;
153 static unsigned long max_x_alloc = 0;
154 static unsigned long total_alloc = 0;
155 static unsigned long total_x_alloc = 0;
156 static unsigned long max_service = 0;
157 static unsigned long total_service = 0;
158
159 static int service_mode = 0 ;
160 static int cleanup_mode = 0 ;
161
set_audit_cleanup_mode(int mode)162 int set_audit_cleanup_mode(int mode)
163 { int old = cleanup_mode; cleanup_mode = mode ; return old;}
164
165 void count_alloc (const char *fname, int line, void *ptr, size_t length, int type);
166 mem *count_find (const char *fname, int line, void *ptr, int type);
167 mem *count_find_and_extract (const char *fname, int line, void *ptr, int type);
168
mem_destroy(ASHashableValue value,void * data)169 void mem_destroy (ASHashableValue value,void *data)
170 {
171 if( data != NULL )
172 {
173 if( deallocated_used < DEALLOC_CACHE_SIZE )
174 deallocated_mem[deallocated_used++] = (mem*)data ;
175 else
176 {
177 if( total_service < sizeof(mem) )
178 {
179 show_error( "it seems that we have too little auditing memory (%lu) while deallocating pointer %p.\n Called from %s:%d", total_service, ((mem*)data)->ptr, ((mem*)data)->fname, ((mem*)data)->line );
180 #ifdef DEBUG_ALLOC_STRICT
181 { char *segv = NULL ; *segv = 0 ; }
182 #endif
183 }else
184 total_service -= sizeof(mem);
185 free( data );
186 }
187 }
188 }
189
190
191 void
count_alloc(const char * fname,int line,void * ptr,size_t length,int type)192 count_alloc (const char *fname, int line, void *ptr, size_t length, int type)
193 {
194 mem *m = NULL;
195 ASHashResult res ;
196
197 if( service_mode > 0 )
198 return ;
199 if( allocs_hash == NULL )
200 {
201 service_mode++ ;
202 allocs_hash = create_ashash( 256, pointer_hash_value, NULL, mem_destroy );
203 service_mode-- ;
204 }
205
206 if( get_hash_item( allocs_hash, (ASHashableValue)ptr, (void**)&m ) == ASH_Success )
207 {
208 show_error( "Same pointer value 0x%lX is being counted twice!\n Called from %s:%d - previously allocated in %s:%d", (unsigned long)ptr, fname, line, m->fname, m->line );
209 print_simple_backtrace();
210 #ifdef DEBUG_ALLOC_STRICT
211 { char *segv = NULL ; *segv = 0 ; }
212 #endif
213 }else if( deallocated_used > 0 )
214 {
215 m = deallocated_mem[--deallocated_used];
216 /* show_warning( "<mem> reusing deallocation cache - element %d, pointer %p auditing service memory used (%lu )\n Called from %s:%d",
217 deallocated_used, m, total_service, fname, line );
218 */ }else
219 {
220 m = calloc (1, sizeof (mem));
221 if( total_service+sizeof(mem) > AUDIT_SERVICE_MEM_LIMIT )
222 {
223 show_error( "<mem> too much auditing service memory used (%lu - was %lu)- aborting, please investigate.\n Called from %s:%d",
224 total_service+sizeof(mem), total_service, fname, line );
225 print_simple_backtrace();
226 output_unfreed_mem (stderr);
227 #ifdef DEBUG_ALLOC_STRICT
228 { char *segv = NULL ; *segv = 0 ; }
229 #endif
230 exit(0);
231 }
232 total_service += sizeof(mem);
233 if( total_service > max_service )
234 max_service = total_service ;
235 }
236 m->fname = fname;
237 m->line = line;
238 m->length = length;
239 m->type = type;
240 m->ptr = ptr;
241 m->freed = 0;
242
243 allocations++;
244 if ((type & 0xff) == C_MEM)
245 {
246 total_alloc += length;
247 if (total_alloc > max_alloc)
248 max_alloc = total_alloc;
249 } else
250 {
251 total_x_alloc += length;
252 if (total_x_alloc > max_x_alloc)
253 max_x_alloc = total_x_alloc;
254 }
255 if (allocations - deallocations > max_allocations)
256 max_allocations = allocations - deallocations;
257
258 if( (res = add_hash_item( allocs_hash, (ASHashableValue)ptr, m )) != ASH_Success )
259 show_error( "failed to log allocation for pointer 0x%lX - result = %d", ptr, res);
260 else
261 {
262 if( total_service+sizeof(ASHashItem) > AUDIT_SERVICE_MEM_LIMIT )
263 {
264 show_error( "<add_hash_item> too much auditing service memory used (%lu - was %lu)- aborting, please investigate.\n Called from %s:%d",
265 total_service+sizeof(ASHashItem), total_service, fname, line );
266 print_simple_backtrace();
267 #ifdef DEBUG_ALLOC_STRICT
268 { char *segv = NULL ; *segv = 0 ; }
269 #endif
270 exit(0);
271 }
272 total_service += sizeof(ASHashItem);
273 if( total_service > max_service )
274 max_service = total_service ;
275 }
276 }
277
278 mem *
count_find(const char * fname,int line,void * ptr,int type)279 count_find (const char *fname, int line, void *ptr, int type)
280 {
281 mem *m;
282
283 if( allocs_hash != NULL )
284 if( get_hash_item( allocs_hash, (ASHashableValue)ptr, (void**)&m) == ASH_Success )
285 if( (m->type & 0xff) == (type & 0xff) )
286 return m ;
287 return NULL ;
288 }
289
290 mem *
count_find_and_extract(const char * fname,int line,void * ptr,int type)291 count_find_and_extract (const char *fname, int line, void *ptr, int type)
292 {
293 mem *m = NULL;
294
295 if( allocs_hash && ptr )
296 {
297 service_mode++ ;
298 if( remove_hash_item (allocs_hash, (ASHashableValue)ptr, (void**)&m, False) == ASH_Success )
299 {
300 if( allocs_hash->items_num <= 0 )
301 destroy_ashash(&allocs_hash);
302 if( (m->type & 0xff) != (type & 0xff) && (m->type & 0xff) != C_IMAGE )
303 {
304 show_error( "while deallocating pointer %p discovered that it was allocated with different type\n Called from %s:%d", ptr, fname, line );
305 #ifdef DEBUG_ALLOC_STRICT
306 { char *segv = NULL ; *segv = 0 ; }
307 #endif
308 }
309 if( total_service < sizeof(ASHashItem) )
310 {
311 show_error( "it seems that we have too little auditing memory (%lu) while deallocating pointer %p.\n Called from %s:%d", total_service, ptr, fname, line );
312 #ifdef DEBUG_ALLOC_STRICT
313 { char *segv = NULL ; *segv = 0 ; }
314 #endif
315 }else
316 total_service -= sizeof(ASHashItem);
317 }
318 service_mode-- ;
319 }
320 if( m )
321 {
322 if ((m->type & 0xff) == C_MEM)
323 total_alloc -= m->length;
324 else
325 total_x_alloc -= m->length;
326 deallocations++;
327 }
328 return m;
329 }
330
331 void *
countmalloc(const char * fname,int line,size_t length)332 countmalloc (const char *fname, int line, size_t length)
333 {
334 void *ptr;
335 if( (int)length < 0 )
336 {
337 fprintf( stderr, "too large malloc of %u from %s:%d\n", length, fname, line );
338 #ifdef DEBUG_ALLOC_STRICT
339 { char *segv = NULL ; *segv = 0 ; }
340 #endif
341 }
342 ptr = safemalloc (length);
343 count_alloc (fname, line, ptr, length, C_MEM | C_MALLOC);
344 return ptr;
345 }
346
347 void *
countcalloc(const char * fname,int line,size_t nrecords,size_t length)348 countcalloc (const char *fname, int line, size_t nrecords, size_t length)
349 {
350 void *ptr = calloc (nrecords, length);
351
352 if( (int)(length*nrecords) < 0 )
353 {
354 fprintf( stderr, "too large calloc of %u from %s:%d\n", length*nrecords, fname, line );
355 #ifdef DEBUG_ALLOC_STRICT
356 { char *segv = NULL ; *segv = 0 ; }
357 #endif
358 }
359 count_alloc (fname, line, ptr, nrecords * length, C_MEM | C_CALLOC);
360 return ptr;
361 }
362
363 void *
countrealloc(const char * fname,int line,void * ptr,size_t length)364 countrealloc (const char *fname, int line, void *ptr, size_t length)
365 {
366 if (ptr != NULL && length == 0)
367 countfree (fname, line, ptr);
368 if (length == 0)
369 return NULL;
370 if (ptr != NULL)
371 {
372 mem *m = NULL;
373 ASHashResult res ;
374
375 if( allocs_hash != NULL )
376 {
377 service_mode++ ;
378 if( remove_hash_item (allocs_hash, (ASHashableValue)ptr, (void**)&m, False) == ASH_Success )
379 if( (m->type & 0xff) != C_MEM )
380 {
381 show_error( "while deallocating pointer 0x%lX discovered that it was allocated with different type", ptr );
382 #ifdef DEBUG_ALLOC_STRICT
383 { char *segv = NULL ; *segv = 0 ; }
384 #endif
385 m = NULL ;
386 }
387 service_mode-- ;
388 }
389 if (m == NULL)
390 {
391 show_error ("countrealloc:attempt in %s:%d to realloc memory(%p) that was never allocated!\n",
392 fname, line, ptr);
393 print_simple_backtrace();
394 #ifdef DEBUG_ALLOC_STRICT
395 { char *segv = NULL ; *segv = 0 ; }
396 #endif
397 return NULL;
398 }
399 if ((m->type & 0xff) == C_MEM)
400 {
401 total_alloc -= m->length;
402 total_alloc += length;
403 if (total_alloc > max_alloc)
404 max_alloc = total_alloc;
405 } else
406 {
407 total_x_alloc -= m->length;
408 total_x_alloc += length;
409 if (total_x_alloc > max_x_alloc)
410 max_x_alloc = total_x_alloc;
411 }
412 m->fname = fname;
413 m->line = line;
414 m->length = length;
415 m->type = C_MEM | C_REALLOC;
416 m->ptr = realloc (ptr, length);
417 m->freed = 0;
418 ptr = m->ptr;
419 if( (res = add_hash_item( allocs_hash, (ASHashableValue)ptr, m )) != ASH_Success )
420 {
421 show_error( "failed to log allocation for pointer 0x%lX - result = %d", ptr, res);
422 #ifdef DEBUG_ALLOC_STRICT
423 { char *segv = NULL ; *segv = 0 ; }
424 #endif
425 }
426 reallocations++;
427 } else
428 ptr = countmalloc (fname, line, length);
429
430 return ptr;
431 }
432
433 void
countfree(const char * fname,int line,void * ptr)434 countfree (const char *fname, int line, void *ptr)
435 {
436 mem *m ;
437
438 if( service_mode > 0 || allocs_hash == NULL )
439 return ;
440
441 if (ptr == NULL)
442 {
443 show_error("countfree:attempt to free NULL memory in %s:%d", fname, line);
444 #ifdef DEBUG_ALLOC_STRICT
445 { char *segv = NULL ; *segv = 0 ; }
446 #endif
447 return;
448 }
449
450 m = count_find_and_extract (fname, line, ptr, C_MEM);
451 if (m == NULL)
452 {
453 if( cleanup_mode == 0 )
454 {
455 show_error( "countfree:attempt in %s:%d to free memory(%p) that was never allocated!", fname, line, ptr);
456 #ifdef DEBUG_ALLOC_STRICT
457 { char *segv = NULL ; *segv = 0 ; }
458 #endif
459 }
460 return;
461 }
462 #if 0
463 // this is invalid code!!
464 if (m1->freed > 0)
465 {
466 fprintf (stderr, "%s:mem already freed %d time(s)!\n", __FUNCTION__, m1->freed);
467 fprintf (stderr, "%s:freed from %s:%d\n", __FUNCTION__, (*m1).fname, (*m1).line);
468 fprintf (stderr, "%s:called from %s:%d\n", __FUNCTION__, fname, line);
469 #ifdef DEBUG_ALLOC_STRICT
470 { char *segv = NULL ; *segv = 0 ; }
471 #endif
472 /* exit (1); */
473 } else
474 safefree (m1->ptr);
475 m1->freed++;
476 m1->fname = fname;
477 m1->line = line;
478 #else
479 safefree (m->ptr);
480 mem_destroy( (ASHashableValue)(void*)NULL, m );
481 #endif
482 }
483
484 ASHashResult
countadd_hash_item(const char * fname,int line,struct ASHashTable * hash,ASHashableValue value,void * data)485 countadd_hash_item (const char *fname, int line, struct ASHashTable *hash, ASHashableValue value, void *data )
486 {
487 ASHashResult res = add_hash_item(hash, value, data );
488
489 if( res == ASH_Success )
490 count_alloc (fname, line, hash->most_recent, sizeof(ASHashItem), C_MEM | C_ADD_HASH_ITEM);
491 return res;
492 }
493
countadd_mystrdup(const char * fname,int line,const char * a)494 char* countadd_mystrdup(const char *fname, int line, const char *a)
495 {
496 char *ptr = mystrdup(a);
497
498 if( a != NULL )
499 count_alloc (fname, line, ptr, strlen(ptr)+1, C_MEM | C_MYSTRDUP);
500 return ptr;
501 }
502
countadd_mystrndup(const char * fname,int line,const char * a,int len)503 char* countadd_mystrndup(const char *fname, int line, const char *a, int len)
504 {
505 char *ptr = mystrndup(a, len );
506
507 if( a != NULL )
508 count_alloc (fname, line, ptr, strlen(ptr)+1, C_MEM | C_MYSTRNDUP);
509 return ptr;
510 }
511
512 void
output_unfreed_mem(FILE * stream)513 output_unfreed_mem (FILE *stream)
514 {
515 ASHashIterator i;
516
517 if( stream == NULL )
518 stream = stderr ;
519 fprintf (stream, "===============================================================================\n");
520 fprintf (stream, "Memory audit: %s\n", ApplicationName);
521 fprintf (stream, "\n");
522 fprintf (stream, " Total allocs: %lu\n", allocations);
523 fprintf (stream, " Total reallocs: %lu\n", reallocations);
524 fprintf (stream, " Total deallocs: %lu\n", deallocations);
525 fprintf (stream, "Max allocs at any one time: %lu\n", max_allocations);
526 fprintf (stream, "Lost audit memory: %lu\n", total_service - deallocated_used*sizeof(mem));
527 fprintf (stream, " Lost memory: %lu\n", total_alloc);
528 fprintf (stream, " Lost X memory: %lu\n", total_x_alloc);
529 fprintf (stream, " Max audit memory: %lu\n", max_service);
530 fprintf (stream, " Max memory used: %lu\n", max_alloc);
531 fprintf (stream, "Max X memory used: %lu\n", max_x_alloc);
532 fprintf (stream, "\n");
533 fprintf (stream, "List of unfreed memory\n");
534 fprintf (stream, "----------------------\n");
535 fprintf (stream, "allocating function |line |length |pointer |type (subtype)\n");
536 fprintf (stream, "-----------------------+-----+-------+-----------+--------------\n");
537 if( start_hash_iteration( allocs_hash, &i ) )
538 do
539 {
540 register mem *m;
541 m = curr_hash_data( &i );
542 if( m == NULL )
543 {
544 fprintf (stream, "hmm, wierd, encoutered NULL pointer while trying to check allocation record for %p!", (void*)((*(i.curr_item))->value));
545 continue;
546 }else if (m->freed == 0)
547 {
548 fprintf (stream, "%23s|%-5d|%-7d|0x%08x ", m->fname, m->line, m->length, (unsigned int)m->ptr);
549 switch (m->type & 0xff)
550 {
551 case C_MEM:
552 fprintf (stream, "| malloc");
553 switch (m->type & ~0xff)
554 {
555 case C_MALLOC:
556 fprintf (stream, " (malloc)");
557 break;
558 case C_CALLOC:
559 fprintf (stream, " (calloc)");
560 break;
561 case C_REALLOC:
562 fprintf (stream, " (realloc)");
563 break;
564 case C_ADD_HASH_ITEM:
565 fprintf (stream, " (add_hash_item)");
566 break;
567 case C_MYSTRDUP:
568 fprintf (stream, " (mystrdup)");
569 break;
570 case C_MYSTRNDUP:
571 fprintf (stream, " (mystrndup)");
572 break;
573 }
574 /* if it seems to be a string, print it */
575 {
576 int i;
577 const unsigned char *ptr = m->ptr;
578
579 for (i = 0; i < m->length; i++)
580 {
581 if (ptr[i] == '\0')
582 break;
583 /* don't print strings containing non-space control characters or high ASCII */
584 if ((ptr[i] <= 0x20 && !isspace (ptr[i])) || ptr[i] >= 0x80)
585 i = m->length;
586 }
587 if (i < m->length)
588 fprintf (stream, " '%s'", ptr);
589 }
590 break;
591 case C_PIXMAP:
592 fprintf (stream, "| pixmap");
593 switch (m->type & ~0xff)
594 {
595 case C_CREATEPIXMAP:
596 fprintf (stream, " (XCreatePixmap)");
597 break;
598 case C_BITMAPFROMDATA:
599 fprintf (stream, " (XCreateBitmapFromData)");
600 break;
601 case C_FROMBITMAP:
602 fprintf (stream, " (XCreatePixmapFromBitmapData)");
603 break;
604 }
605 break;
606 case C_GC:
607 fprintf (stream, "| gc (XCreateGC)");
608 break;
609 case C_IMAGE:
610 fprintf (stream, "| image");
611 switch (m->type & ~0xff)
612 {
613 case 0:
614 fprintf (stream, " (XCreateImage)");
615 break;
616 case C_GETIMAGE:
617 fprintf (stream, " (XGetImage)");
618 break;
619 case C_SUBIMAGE:
620 fprintf (stream, " (XSubImage)");
621 break;
622 }
623 break;
624 case C_XMEM:
625 fprintf (stream, "| X mem");
626 switch (m->type & ~0xff)
627 {
628 case C_XGETWINDOWPROPERTY:
629 fprintf (stream, " (XGetWindowProperty)");
630 break;
631 case C_XLISTPROPERTIES:
632 fprintf (stream, " (XListProperties)");
633 break;
634 case C_XGETTEXTPROPERTY:
635 fprintf (stream, " (XGetTextProperty)");
636 break;
637 case C_XALLOCCLASSHINT :
638 fprintf (stream, " (XAllocClassHint)");
639 break;
640 case C_XALLOCSIZEHINTS :
641 fprintf (stream, " (XAllocSizeHints)");
642 break;
643 case C_XQUERYTREE:
644 fprintf (stream, " (XQueryTree)");
645 break;
646 case C_XGETWMHINTS:
647 fprintf (stream, " (XGetWMHints)");
648 break;
649 case C_XGETWMPROTOCOLS:
650 fprintf (stream, " (XGetWMProtocols)");
651 break;
652 case C_XGETWMNAME:
653 fprintf (stream, " (XGetWMName)");
654 break;
655 case C_XGETCLASSHINT:
656 fprintf (stream, " (XGetClassHint)");
657 break;
658 case C_XGETATOMNAME:
659 fprintf (stream, " (XGetAtomName)");
660 break;
661 case C_XSTRINGLISTTOTEXTPROPERTY:
662 fprintf (stream, " (XStringListToTextProperty)");
663 break;
664 }
665 break;
666 }
667 fprintf (stream, "\n");
668 }
669 }while( next_hash_item(&i) );
670 fprintf (stream, "===============================================================================\n");
671 }
672
673 void
spool_unfreed_mem(char * filename,const char * comments)674 spool_unfreed_mem (char *filename, const char *comments)
675 {
676 FILE *spoolfile = fopen(filename, "w+");
677 if( spoolfile )
678 {
679 fprintf( spoolfile, "%s: Memory Usage Snapshot <%s>", ApplicationName, comments?comments:"no comments\n" );
680 output_unfreed_mem( spoolfile );
681 fclose( spoolfile );
682 }
683 }
684
print_unfreed_mem()685 void print_unfreed_mem()
686 {
687 output_unfreed_mem(NULL);
688 }
689
690
691 void
print_unfreed_mem_stats(const char * file,const char * func,int line,const char * msg)692 print_unfreed_mem_stats (const char *file, const char *func, int line, const char *msg)
693 {
694 if( msg )
695 fprintf( stderr, "%s:%s:%s:%d: Memory audit %s\n", ApplicationName, file, func, line, msg );
696 fprintf( stderr, "%s:%s:%s:%d: Memory audit counts: allocs %lu, reallocs: %lu, deallocs: %lu, max simultaneous %lu\n",
697 ApplicationName, file, func, line, allocations, reallocations, deallocations, max_allocations);
698 fprintf( stderr, "%s:%s:%s:%d: Memory audit used memory: private %lu, X %lu, audit %lu, max private %lu, max X %lu, max audit %lu\n",
699 ApplicationName, file, func, line, total_alloc, total_x_alloc, total_service - deallocated_used*sizeof(mem), max_alloc, max_x_alloc, max_service);
700 }
701
702
703 #ifndef X_DISPLAY_MISSING
704 Pixmap
count_xcreatepixmap(const char * fname,int line,Display * display,Drawable drawable,unsigned int width,unsigned int height,unsigned int depth)705 count_xcreatepixmap (const char *fname, int line, Display * display,
706 Drawable drawable, unsigned int width, unsigned int height, unsigned int depth)
707 {
708 Pixmap pmap = XCreatePixmap (display, drawable, width, height, depth);
709
710 if (pmap == None)
711 return None;
712 count_alloc (fname, line, (void *)pmap, width * height * depth / 8, C_PIXMAP | C_CREATEPIXMAP);
713 return pmap;
714 }
715
716
717 Pixmap
count_xcreatebitmapfromdata(const char * fname,int line,Display * display,Drawable drawable,char * data,unsigned int width,unsigned int height)718 count_xcreatebitmapfromdata (const char *fname, int line, Display * display,
719 Drawable drawable, char *data, unsigned int width, unsigned int height)
720 {
721 Pixmap pmap = XCreateBitmapFromData (display, drawable, data, width, height);
722
723 if (pmap == None)
724 return None;
725 count_alloc (fname, line, (void *)pmap, width * height / 8, C_PIXMAP | C_BITMAPFROMDATA);
726 return pmap;
727 }
728
729 Pixmap
count_xcreatepixmapfrombitmapdata(const char * fname,int line,Display * display,Drawable drawable,char * data,unsigned int width,unsigned int height,unsigned long fg,unsigned long bg,unsigned int depth)730 count_xcreatepixmapfrombitmapdata (const char *fname, int line,
731 Display * display, Drawable drawable,
732 char *data, unsigned int width,
733 unsigned int height, unsigned long fg, unsigned long bg, unsigned int depth)
734 {
735 Pixmap pmap = XCreatePixmapFromBitmapData (display, drawable, data, width, height,
736 fg,
737 bg, depth);
738
739 if (pmap == None)
740 return None;
741 count_alloc (fname, line, (void *)pmap, width * height * depth / 8, C_PIXMAP | C_FROMBITMAP);
742 return pmap;
743 }
744
745 int
count_xfreepixmap(const char * fname,int line,Display * display,Pixmap pmap)746 count_xfreepixmap (const char *fname, int line, Display * display, Pixmap pmap)
747 {
748 mem *m = count_find_and_extract (fname, line, (void *)pmap, C_PIXMAP);
749
750 if (pmap == None)
751 {
752 show_error("count_xfreepixmap:attempt to free None pixmap in %s:%d", fname, line);
753 return !Success;
754 }
755
756 if (m == NULL)
757 {
758 show_error ("count_xfreepixmap:attempt in %s:%d to free Pixmap(0x%X) that was never created, or already freed!",
759 fname, line, (unsigned int)pmap);
760 raise( SIGUSR2 );
761 XFreePixmap (display, pmap );
762 return !Success;
763 }
764 /* fprintf (stderr,"%s:%s:%d freeing Pixmap(0x%X)\n", __FUNCTION__, fname, line, (unsigned int)pmap);
765 */
766
767 XFreePixmap (display, pmap);
768 mem_destroy( (ASHashableValue)(void*)NULL, m );
769 return Success;
770 }
771
772 GC
count_xcreategc(const char * fname,int line,Display * display,Drawable drawable,unsigned int mask,XGCValues * values)773 count_xcreategc (const char *fname, int line, Display * display,
774 Drawable drawable, unsigned int mask, XGCValues * values)
775 {
776 GC gc = XCreateGC (display, drawable, mask, values);
777
778 if (gc == None)
779 return None;
780 count_alloc (fname, line, (void *)gc, sizeof (XGCValues), C_GC);
781 return gc;
782 }
783
784 int
count_xfreegc(const char * fname,int line,Display * display,GC gc)785 count_xfreegc (const char *fname, int line, Display * display, GC gc)
786 {
787 mem *m = count_find_and_extract (fname, line, (void *)gc, C_GC);
788
789 if (gc == None)
790 {
791 show_error( "count_xfreegc:attempt to free None GC in %s:%d", fname, line);
792 return !Success;
793 }
794
795 if (m == NULL)
796 {
797 show_error( "count_xfreegc:attempt in %s:%d to free a GC (0x%X)that was never created or already destroyed!",
798 fname, line, (unsigned int)gc);
799 return !Success;
800 }
801
802 XFreeGC (display, gc);
803 mem_destroy( (ASHashableValue)(void*)NULL, m );
804 return Success;
805 }
806
807 XImage *
count_xcreateimage(const char * fname,int line,Display * display,Visual * visual,unsigned int depth,int format,int offset,char * data,unsigned int width,unsigned int height,int bitmap_pad,int byte_per_line)808 count_xcreateimage (const char *fname, int line, Display * display,
809 Visual * visual, unsigned int depth, int format,
810 int offset, char *data, unsigned int width, unsigned int height, int bitmap_pad, int byte_per_line)
811 {
812 XImage *image = XCreateImage (display, visual, depth, format, offset, data, width,
813 height,
814 bitmap_pad, byte_per_line);
815
816 if (image == NULL)
817 return NULL;
818 count_alloc (fname, line, (void *)image, sizeof (*image), C_IMAGE);
819 return image;
820 }
821
822 XImage *
count_xgetimage(const char * fname,int line,Display * display,Drawable drawable,int x,int y,unsigned int width,unsigned int height,unsigned long plane_mask,int format)823 count_xgetimage (const char *fname, int line, Display * display,
824 Drawable drawable, int x, int y, unsigned int width,
825 unsigned int height, unsigned long plane_mask, int format)
826 {
827 XImage *image = XGetImage (display, drawable, x, y, width, height, plane_mask,
828
829 format);
830
831 if (image == NULL)
832 return NULL;
833 count_alloc (fname, line, (void *)image,
834 sizeof (*image) + image->height * image->bytes_per_line, C_IMAGE | C_GETIMAGE);
835 return image;
836 }
837
838 XImage *
count_xsubimage(const char * fname,int line,XImage * img,int x,int y,unsigned int width,unsigned int height)839 count_xsubimage (const char *fname, int line, XImage *img,
840 int x, int y, unsigned int width, unsigned int height )
841
842 {
843 XImage *image = (*(img->f.sub_image))(img, x, y, width, height);
844
845 if (image == NULL)
846 return NULL;
847 count_alloc (fname, line, (void *)image,
848 sizeof (*image) + image->height * image->bytes_per_line, C_IMAGE | C_SUBIMAGE);
849 return image;
850 }
851
852 int
count_xdestroyimage(const char * fname,int line,XImage * image)853 count_xdestroyimage (const char *fname, int line, XImage * image)
854 {
855 mem *m;
856 void *image_data;
857 void *image_obdata;
858
859 if (image == NULL)
860 {
861 show_error("count_xdestroyimage:attempt to free NULL XImage in %s:%d", fname, line);
862 return BadValue;
863 }
864 image_data = (void *)(image->data);
865 image_obdata = (void *)(image->obdata);
866
867 if ((m = count_find (fname, line, (void *)image, C_IMAGE)) == NULL)
868 /* can also be of C_MEM type if we allocated it ourselvs */
869 if ((m = count_find (fname, line, (void *)image, C_MEM)) == NULL)
870 {
871 show_error("count_xdestroyimage:attempt in %s:%d to destroy an XImage that was never created or already destroyed.\n",
872 fname, line);
873 return !Success;
874 }
875
876 (*image->f.destroy_image) (image);
877
878 if ((m = count_find_and_extract (fname, line, (void *)image, C_IMAGE)) == NULL)
879 /* can also be of C_MEM type if we allocated it ourselvs */
880 m = count_find_and_extract (fname, line, (void *)image, C_MEM);
881 if (m)
882 mem_destroy( (ASHashableValue)(void*)NULL, m );
883
884 /* find and free the image->data pointer if it is in our list */
885 if( image_data )
886 if ((m = count_find_and_extract (fname, line, image_data, C_MEM)) != NULL)
887 mem_destroy( (ASHashableValue)(void*)NULL, m );
888
889 /* find and free the image->obdata pointer if it is in our list */
890 if( image_obdata )
891 if ((m = count_find_and_extract (fname, line, image_obdata, C_MEM)) != NULL)
892 mem_destroy( (ASHashableValue)(void*)NULL, m );
893
894 return Success;
895 }
896
897 int
count_xgetwindowproperty(const char * fname,int line,Display * display,Window w,Atom property,long long_offset,long long_length,Bool delete,Atom req_type,Atom * actual_type_return,int * actual_format_return,unsigned long * nitems_return,unsigned long * bytes_after_return,unsigned char ** prop_return)898 count_xgetwindowproperty (const char *fname, int line, Display * display,
899 Window w, Atom property, long long_offset,
900 long long_length, Bool delete, Atom req_type,
901 Atom * actual_type_return,
902 int *actual_format_return,
903 unsigned long *nitems_return, unsigned long *bytes_after_return, unsigned char **prop_return)
904 {
905 int val;
906 unsigned long my_nitems_return;
907
908 val =
909 XGetWindowProperty (display, w, property, long_offset, long_length,
910 delete, req_type, actual_type_return,
911 actual_format_return, &my_nitems_return, bytes_after_return, prop_return);
912 if (val == Success && my_nitems_return)
913 count_alloc (fname, line, (void *)*prop_return,
914 my_nitems_return * *actual_format_return / 8, C_XMEM | C_XGETWINDOWPROPERTY);
915 *nitems_return = my_nitems_return; /* need to do this in case bytes_after_return and nitems_return point to the same var */
916 return val;
917 }
918
919 Atom *
count_xlistproperties(const char * fname,int line,Display * display,Window w,int * props_num)920 count_xlistproperties( const char *fname, int line, Display * display,
921 Window w, int *props_num )
922 {
923 Atom *props ;
924
925 props = XListProperties (display, w, props_num);
926 if( props != NULL && *props_num > 0 )
927 count_alloc (fname, line, (void *)props,
928 (*props_num)*sizeof(Atom), C_XMEM | C_XLISTPROPERTIES);
929 return props;
930 }
931
932
933 Status
count_xgettextproperty(const char * fname,int line,Display * display,Window w,XTextProperty * trg,Atom property)934 count_xgettextproperty(const char *fname, int line, Display * display, Window w,
935 XTextProperty *trg, Atom property)
936 {
937 Status val;
938
939 val = XGetTextProperty(display,w,trg,property);
940 if (val && trg->value )
941 count_alloc (fname, line, (void *)(trg->value), strlen(trg->value)+1, C_XMEM | C_XGETTEXTPROPERTY );
942 return val;
943 }
944
945 XClassHint *
count_xallocclasshint(const char * fname,int line)946 count_xallocclasshint(const char *fname, int line)
947 {
948 XClassHint *wmclass ;
949 wmclass = XAllocClassHint();
950 if( wmclass != NULL )
951 count_alloc (fname, line, (void *)wmclass, sizeof(XClassHint), C_XMEM | C_XALLOCCLASSHINT );
952 return wmclass;
953 }
954
955 XSizeHints *
count_xallocsizehints(const char * fname,int line)956 count_xallocsizehints(const char *fname, int line)
957 {
958 XSizeHints *size_hints ;
959 size_hints = XAllocSizeHints();
960 if( size_hints != NULL )
961 count_alloc (fname, line, (void *)size_hints, sizeof(XSizeHints), C_XMEM | C_XALLOCSIZEHINTS );
962 return size_hints;
963 }
964
965
966 Status
count_xquerytree(const char * fname,int line,Display * display,Window w,Window * root_return,Window * parent_return,Window ** children_return,unsigned int * nchildren_return)967 count_xquerytree (const char *fname, int line, Display * display, Window w,
968 Window * root_return, Window * parent_return,
969 Window ** children_return, unsigned int *nchildren_return)
970 {
971 Status val;
972
973 val = XQueryTree (display, w, root_return, parent_return, children_return, nchildren_return);
974 if (val && *nchildren_return)
975 count_alloc (fname, line, (void *)*children_return, *nchildren_return * sizeof (Window), C_XMEM | C_XQUERYTREE);
976 return val;
977 }
978
979 /* really returns XWMHints*, but to avoid requiring extra includes, we'll return void* */
980 void *
count_xgetwmhints(const char * fname,int line,Display * display,Window w)981 count_xgetwmhints (const char *fname, int line, Display * display, Window w)
982 {
983 XWMHints *val;
984
985 val = XGetWMHints (display, w);
986 if (val != NULL)
987 count_alloc (fname, line, (void *)val, sizeof (XWMHints), C_XMEM | C_XGETWMHINTS);
988 return (void *)val;
989 }
990
991 /* protocols_return is really Atom**, but to avoid extra includes, we'll use void* */
992 Status
count_xgetwmprotocols(const char * fname,int line,Display * display,Window w,void * protocols_return,int * count_return)993 count_xgetwmprotocols (const char *fname, int line, Display * display,
994 Window w, void *protocols_return, int *count_return)
995 {
996 Status val;
997
998 val = XGetWMProtocols (display, w, (Atom **) protocols_return, count_return);
999 if (val && *count_return)
1000 count_alloc (fname, line, *(void **)protocols_return,
1001 *count_return * sizeof (Atom), C_XMEM | C_XGETWMPROTOCOLS);
1002 return val;
1003 }
1004
1005 /* text_prop_return is really XTextProperty*, but to avoid extra includes, we'll use void* */
1006 Status
count_xgetwmname(const char * fname,int line,Display * display,Window w,void * text_prop_return)1007 count_xgetwmname (const char *fname, int line, Display * display, Window w, void *text_prop_return)
1008 {
1009 Status val;
1010 XTextProperty *prop = text_prop_return;
1011
1012 val = XGetWMName (display, w, prop);
1013 if (val && prop->nitems)
1014 count_alloc (fname, line, (void *)prop->value, prop->nitems * prop->format / 8, C_XMEM | C_XGETWMNAME);
1015 return val;
1016 }
1017
1018 /* class_hints_return is really XTextProperty*, but to avoid extra includes, we'll use void* */
1019 Status
count_xgetclasshint(const char * fname,int line,Display * display,Window w,void * class_hint_return)1020 count_xgetclasshint (const char *fname, int line, Display * display, Window w, void *class_hint_return)
1021 {
1022 Status val;
1023 XClassHint *prop = class_hint_return;
1024
1025 val = XGetClassHint (display, w, prop);
1026 if (val && prop->res_name)
1027 count_alloc (fname, line, (void *)prop->res_name, strlen (prop->res_name), C_XMEM | C_XGETCLASSHINT);
1028 if (val && prop->res_class)
1029 count_alloc (fname, line, (void *)prop->res_class, strlen (prop->res_class), C_XMEM | C_XGETCLASSHINT);
1030 return val;
1031 }
1032
1033 char *
count_xgetatomname(const char * fname,int line,Display * display,Atom atom)1034 count_xgetatomname (const char *fname, int line, Display * display, Atom atom)
1035 {
1036 char *val = XGetAtomName (display, atom);
1037
1038 if (val != NULL)
1039 count_alloc (fname, line, (void *)val, strlen (val), C_XMEM | C_XGETATOMNAME);
1040 return val;
1041 }
1042
1043 /* text_prop_return is really XTextProperty*, but to avoid extra includes, we'll use void* */
1044 Status
count_xstringlisttotextproperty(const char * fname,int line,char ** list,int count,void * text_prop_return)1045 count_xstringlisttotextproperty (const char *fname, int line, char **list, int count, void *text_prop_return)
1046 {
1047 Status val;
1048 XTextProperty *prop = text_prop_return;
1049
1050 val = XStringListToTextProperty (list, count, prop);
1051 if (val && prop->nitems)
1052 count_alloc (fname, line, (void *)prop->value,
1053 prop->nitems * prop->format / 8, C_XMEM | C_XSTRINGLISTTOTEXTPROPERTY);
1054 return val;
1055 }
1056
1057 int
count_xfree(const char * fname,int line,void * data)1058 count_xfree (const char *fname, int line, void *data)
1059 {
1060 mem *m = count_find_and_extract (fname, line, (void *)data, C_XMEM);
1061
1062 if (m == NULL)
1063 {
1064 show_error("count_xfree:attempt to free NULL X memory in %s:%d", fname, line);
1065 return !Success;
1066 }
1067
1068 if (m == NULL)
1069 {
1070 show_error("count_xfree:attempt in %s:%d to free X memory (%p) that was never allocated or already freed!",
1071 fname, line, data);
1072 return !Success;
1073 }
1074
1075 XFree (data);
1076 mem_destroy( (ASHashableValue)(void*)NULL, m );
1077 return Success;
1078 }
1079
1080 #endif /* #ifndef X_DISPLAY_MISSING */
1081
1082