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