1 /* ----------------------------------------------------------------------------
2 @COPYRIGHT :
3 Copyright 1993,1994,1995 David MacDonald,
4 McConnell Brain Imaging Centre,
5 Montreal Neurological Institute, McGill University.
6 Permission to use, copy, modify, and distribute this
7 software and its documentation for any purpose and without
8 fee is hereby granted, provided that the above copyright
9 notice appear in all copies. The author and McGill University
10 make no representations about the suitability of this
11 software for any purpose. It is provided "as is" without
12 express or implied warranty.
13 ---------------------------------------------------------------------------- */
14
15 #include <internal_volume_io.h>
16
17 /* ----------------------------- MNI Header -----------------------------------
18 @NAME : alloc_check.c
19 @INPUT :
20 @OUTPUT :
21 @RETURNS :
22 @DESCRIPTION: Maintains a skiplist structure to list all memory allocated,
23 : and check for errors such as freeing a pointer twice or
24 : overlapping allocations.
25 @METHOD :
26 @GLOBALS :
27 @CALLS :
28 @CREATED : David MacDonald
29 @MODIFIED :
30 ---------------------------------------------------------------------------- */
31
32 #define MAX_SKIP_LEVELS 50
33 #define SKIP_P 0.5
34
35 #define MEMORY_DIFFERENCE 1000000
36
37 typedef struct skip_entry
38 {
39 void *ptr;
40 size_t n_bytes;
41 STRING source_file;
42 int line_number;
43 int sequence_number;
44 struct skip_entry *forward[1];
45 } skip_entry;
46
47 typedef struct
48 {
49 size_t next_memory_threshold;
50 size_t total_memory_allocated;
51 skip_entry *header;
52 int level;
53 } alloc_struct;
54
55 typedef struct
56 {
57 skip_entry *update[MAX_SKIP_LEVELS];
58 } update_struct;
59
60 static void update_total_memory( alloc_struct *, size_t );
61 static int get_random_level( void );
62 static void output_entry( FILE *, skip_entry * );
63 static BOOLEAN size_display_enabled( void );
64 static size_t skip_alloc_size = 0;
65
66 typedef void *alloc_ptr;
67
68 #define ALLOC_SKIP_STRUCT( ptr, n_level ) \
69 (ptr) = (skip_entry *) malloc( \
70 (sizeof(skip_entry)+((size_t)(n_level)-1) * sizeof(skip_entry *)) );
71
72 /* ----------------------------- MNI Header -----------------------------------
73 @NAME : initialize_alloc_list
74 @INPUT : alloc_list
75 @OUTPUT :
76 @RETURNS :
77 @DESCRIPTION: Initializes the allocation list to empty.
78 @METHOD :
79 @GLOBALS :
80 @CALLS :
81 @CREATED : David MacDonald
82 @MODIFIED :
83 ---------------------------------------------------------------------------- */
84
initialize_alloc_list(alloc_struct * alloc_list)85 static void initialize_alloc_list(
86 alloc_struct *alloc_list )
87 {
88 int i;
89
90 alloc_list->next_memory_threshold = MEMORY_DIFFERENCE;
91 alloc_list->total_memory_allocated = 0;
92
93 ALLOC_SKIP_STRUCT( alloc_list->header, MAX_SKIP_LEVELS );
94 skip_alloc_size += sizeof(skip_entry)+(MAX_SKIP_LEVELS-1) *
95 sizeof(skip_entry *);
96 alloc_list->level = 1;
97
98 for_less( i, 0, MAX_SKIP_LEVELS )
99 alloc_list->header->forward[i] = (skip_entry *) 0;
100 }
101
102 /* ----------------------------- MNI Header -----------------------------------
103 @NAME : check_initialized_alloc_list
104 @INPUT : alloc_list
105 @OUTPUT :
106 @RETURNS :
107 @DESCRIPTION: Checks to make sure the allocation list is initialized.
108 @METHOD :
109 @GLOBALS :
110 @CALLS :
111 @CREATED : 1993 David MacDonald
112 @MODIFIED :
113 ---------------------------------------------------------------------------- */
114
check_initialized_alloc_list(alloc_struct * alloc_list)115 static void check_initialized_alloc_list(
116 alloc_struct *alloc_list )
117 {
118 static BOOLEAN first = TRUE;
119
120 if( first )
121 {
122 first = FALSE;
123 initialize_alloc_list( alloc_list );
124 }
125 }
126
127 /* ----------------------------- MNI Header -----------------------------------
128 @NAME : find_pointer_position
129 @INPUT : alloc_list
130 : ptr
131 @OUTPUT : update
132 @RETURNS : TRUE if found
133 @DESCRIPTION: Searches the alloc_list for the given ptr, and sets the update
134 : struct so that it can provide an insert.
135 @METHOD :
136 @GLOBALS :
137 @CALLS :
138 @CREATED : David MacDonald
139 @MODIFIED :
140 ---------------------------------------------------------------------------- */
141
find_pointer_position(alloc_struct * alloc_list,void * ptr,update_struct * update)142 static BOOLEAN find_pointer_position(
143 alloc_struct *alloc_list,
144 void *ptr,
145 update_struct *update )
146 {
147 int i;
148 skip_entry *x;
149 BOOLEAN found;
150
151 x = alloc_list->header;
152
153 for( i = alloc_list->level-1; i >= 0; --i )
154 {
155 while( x->forward[i] != NULL && (void *) x->forward[i]->ptr < ptr )
156 {
157 x = x->forward[i];
158 }
159 update->update[i] = x;
160 }
161
162 x = update->update[0]->forward[0];
163
164 found = (x != NULL) && (x->ptr == ptr);
165
166 return( found );
167 }
168
169 /* ----------------------------- MNI Header -----------------------------------
170 @NAME : insert_ptr_in_alloc_list
171 @INPUT : alloc_list
172 : update - the set of pointers indicating where to insert
173 : ptr }
174 : n_bytes }}
175 : source_file }}} these are recorded in the list
176 : line_number }}
177 : sequence_number }
178 @OUTPUT :
179 @RETURNS :
180 @DESCRIPTION: Records the allocated pointer in the allocation list.
181 @METHOD :
182 @GLOBALS :
183 @CALLS :
184 @CREATED : David MacDonald
185 @MODIFIED :
186 ---------------------------------------------------------------------------- */
187
insert_ptr_in_alloc_list(alloc_struct * alloc_list,update_struct * update,void * ptr,size_t n_bytes,STRING source_file,int line_number,int sequence_number)188 static void insert_ptr_in_alloc_list(
189 alloc_struct *alloc_list,
190 update_struct *update,
191 void *ptr,
192 size_t n_bytes,
193 STRING source_file,
194 int line_number,
195 int sequence_number )
196 {
197 int i, new_level;
198 skip_entry *x;
199
200 new_level = get_random_level();
201
202 if( new_level > alloc_list->level )
203 {
204 for( i = alloc_list->level; i < new_level; ++i )
205 update->update[i] = alloc_list->header;
206
207 alloc_list->level = new_level;
208 }
209
210 ALLOC_SKIP_STRUCT( x, new_level );
211 skip_alloc_size += sizeof(skip_entry)+((size_t)new_level-1) *
212 sizeof(skip_entry *);
213
214 x->ptr = ptr;
215 x->n_bytes = n_bytes;
216 x->source_file = source_file;
217 x->line_number = line_number;
218 x->sequence_number = sequence_number;
219 update_total_memory( alloc_list, n_bytes );
220
221 for( i = 0; i < new_level; ++i )
222 {
223 x->forward[i] = update->update[i]->forward[i];
224 update->update[i]->forward[i] = x;
225 }
226 }
227
228 /* ----------------------------- MNI Header -----------------------------------
229 @NAME : check_overlap
230 @INPUT : update
231 : ptr
232 : n_bytes
233 @OUTPUT : entry
234 @RETURNS : TRUE if an overlap
235 @DESCRIPTION: Checks the new ptr to see if it overlaps with the previous and
236 : following memory allocations in the list, and returns the result.
237 @METHOD :
238 @GLOBALS :
239 @CALLS :
240 @CREATED : David MacDonald
241 @MODIFIED :
242 ---------------------------------------------------------------------------- */
243
check_overlap(alloc_struct * alloc_list,update_struct * update,void * ptr,size_t n_bytes,skip_entry ** entry)244 static BOOLEAN check_overlap(
245 alloc_struct *alloc_list,
246 update_struct *update,
247 void *ptr,
248 size_t n_bytes,
249 skip_entry **entry )
250 {
251 BOOLEAN overlap;
252
253 overlap = FALSE;
254
255 *entry = update->update[0];
256
257 if( *entry != alloc_list->header && *entry != (skip_entry *) 0 )
258 {
259 if( (void *) ((char *) (*entry)->ptr + (*entry)->n_bytes) > ptr )
260 overlap = TRUE;
261 else
262 {
263 (*entry) = (*entry)->forward[0];
264 if( *entry != (skip_entry *) 0 &&
265 (void *) ((char*)ptr + n_bytes) > (*entry)->ptr )
266 overlap = TRUE;
267 }
268 }
269
270 return( overlap );
271 }
272
273 /* ----------------------------- MNI Header -----------------------------------
274 @NAME : remove_ptr_from_alloc_list
275 @INPUT : alloc_list
276 : ptr
277 @OUTPUT : source_file
278 : line_number
279 : sequence_number
280 @RETURNS : TRUE if it existed
281 @DESCRIPTION: Finds and deletes the entry in the skip list associated with
282 : ptr, and returns the information associated with the entry
283 : (source_file, line_number, sequence_number).
284 @METHOD :
285 @GLOBALS :
286 @CALLS :
287 @CREATED : David MacDonald
288 @MODIFIED :
289 ---------------------------------------------------------------------------- */
290
remove_ptr_from_alloc_list(alloc_struct * alloc_list,void * ptr,STRING * source_file,int * line_number,int * sequence_number)291 static BOOLEAN remove_ptr_from_alloc_list(
292 alloc_struct *alloc_list,
293 void *ptr,
294 STRING *source_file,
295 int *line_number,
296 int *sequence_number )
297 {
298 int i;
299 BOOLEAN found;
300 skip_entry *x;
301 update_struct update;
302
303 found = find_pointer_position( alloc_list, ptr, &update );
304
305 if( found )
306 {
307 x = update.update[0]->forward[0];
308
309 *source_file = x->source_file;
310 *line_number = x->line_number;
311 *sequence_number = x->sequence_number;
312
313 update_total_memory( alloc_list, -x->n_bytes );
314
315 for( i = 0; i < alloc_list->level; ++i )
316 {
317 if( update.update[i]->forward[i] != x )
318 break;
319 update.update[i]->forward[i] = x->forward[i];
320 }
321
322 skip_alloc_size -= sizeof(skip_entry) +
323 (size_t) (i-1) * sizeof(skip_entry *);
324
325 free( (alloc_ptr) x );
326
327 while( alloc_list->level > 1 &&
328 alloc_list->header->forward[alloc_list->level-1] ==
329 (skip_entry *) 0 )
330 {
331 --alloc_list->level;
332 }
333 }
334
335 return( found );
336 }
337
338 /* ----------------------------- MNI Header -----------------------------------
339 @NAME : get_random_0_to_1
340 @INPUT :
341 @OUTPUT :
342 @RETURNS : random number
343 @DESCRIPTION: Returns a random number >= 0 and < 1.
344 @METHOD :
345 @GLOBALS :
346 @CALLS :
347 @CREATED : 1993 David MacDonald
348 @MODIFIED :
349 ---------------------------------------------------------------------------- */
350
get_random_0_to_1(void)351 static Real get_random_0_to_1( void )
352 {
353 return( (Real) rand() );
354 }
355
356 /* ----------------------------- MNI Header -----------------------------------
357 @NAME : get_random_level
358 @INPUT :
359 @OUTPUT :
360 @RETURNS : a random level between 1 and MAX_LEVELS
361 @DESCRIPTION: Determines a random level with exponential probability of higher
362 : levels.
363 @METHOD :
364 @GLOBALS :
365 @CALLS :
366 @CREATED : David MacDonald
367 @MODIFIED :
368 ---------------------------------------------------------------------------- */
369
get_random_level(void)370 static int get_random_level( void )
371 {
372 int level;
373
374 level = 1;
375
376 while( get_random_0_to_1() < SKIP_P && level < MAX_SKIP_LEVELS )
377 ++level;
378
379 return( level );
380 }
381
382 /* ----------------------------- MNI Header -----------------------------------
383 @NAME : memory_still_alloced
384 @INPUT : alloc_list
385 @OUTPUT :
386 @RETURNS : TRUE or FALSE
387 @DESCRIPTION: Decides if any memory is still alloced, thus checking for
388 memory leaks.
389 @METHOD :
390 @GLOBALS :
391 @CALLS :
392 @CREATED : David MacDonald
393 @MODIFIED :
394 ---------------------------------------------------------------------------- */
395
memory_still_alloced(alloc_struct * alloc_list)396 static BOOLEAN memory_still_alloced(
397 alloc_struct *alloc_list )
398 {
399 return( alloc_list->header->forward[0] != (skip_entry *) NULL );
400 }
401
402 /* ----------------------------- MNI Header -----------------------------------
403 @NAME : output_alloc_list
404 @INPUT : file
405 : alloc_list
406 @OUTPUT :
407 @RETURNS :
408 @DESCRIPTION: Outputs the list of allocated memory to the file.
409 @METHOD :
410 @GLOBALS :
411 @CALLS :
412 @CREATED : David MacDonald
413 @MODIFIED :
414 ---------------------------------------------------------------------------- */
415
output_alloc_list(FILE * file,alloc_struct * alloc_list)416 static void output_alloc_list(
417 FILE *file,
418 alloc_struct *alloc_list )
419 {
420 skip_entry *ptr;
421
422 ptr = alloc_list->header->forward[0];
423
424 while( ptr != (skip_entry *) 0 )
425 {
426 output_entry( file, ptr );
427 ptr = ptr->forward[0];
428 }
429 }
430
431 /* ----------------------------- MNI Header -----------------------------------
432 @NAME : update_total_memory
433 @INPUT : alloc_list
434 : n_bytes
435 @OUTPUT :
436 @RETURNS :
437 @DESCRIPTION: Adds n_bytes to the size of memory recorded.
438 @METHOD :
439 @GLOBALS :
440 @CALLS :
441 @CREATED : David MacDonald
442 @MODIFIED :
443 ---------------------------------------------------------------------------- */
444
update_total_memory(alloc_struct * alloc_list,size_t n_bytes)445 static void update_total_memory(
446 alloc_struct *alloc_list,
447 size_t n_bytes )
448 {
449 alloc_list->total_memory_allocated += n_bytes;
450
451 if( size_display_enabled() &&
452 alloc_list->total_memory_allocated >
453 alloc_list->next_memory_threshold )
454 {
455 alloc_list->next_memory_threshold = MEMORY_DIFFERENCE *
456 (alloc_list->total_memory_allocated / MEMORY_DIFFERENCE + 1);
457 print( "Memory allocated =%5.1f Megabytes (Overhead = %5.1f Mb)\n",
458 (Real) alloc_list->total_memory_allocated / 1000000.0,
459 (Real) skip_alloc_size / 1000000.0 );
460 }
461 }
462
463 /* ----------------------------- MNI Header -----------------------------------
464 @NAME : print_source_location
465 @INPUT : source_file
466 : line_number
467 : sequence_number
468 @OUTPUT :
469 @RETURNS :
470 @DESCRIPTION: Prints the information about a particular allocation.
471 @METHOD :
472 @GLOBALS :
473 @CALLS :
474 @CREATED : David MacDonald
475 @MODIFIED :
476 ---------------------------------------------------------------------------- */
477
print_source_location(STRING source_file,int line_number,int sequence_number)478 static void print_source_location(
479 STRING source_file,
480 int line_number,
481 int sequence_number )
482 {
483 print_error( "%s:%d\t%d'th alloc",
484 source_file, line_number, sequence_number );
485 }
486
487 /* ----------------------------- MNI Header -----------------------------------
488 @NAME : output_entry
489 @INPUT : file
490 : entry
491 @OUTPUT :
492 @RETURNS :
493 @DESCRIPTION: Outputs the information about an allocation entry to the file.
494 @METHOD :
495 @GLOBALS :
496 @CALLS :
497 @CREATED : David MacDonald
498 @MODIFIED :
499 ---------------------------------------------------------------------------- */
500
output_entry(FILE * file,skip_entry * entry)501 static void output_entry(
502 FILE *file,
503 skip_entry *entry )
504 {
505 (void) fprintf( file, "%s:%d\t%d'th alloc\n",
506 entry->source_file,
507 entry->line_number,
508 entry->sequence_number );
509 }
510
511 /*
512 --------------------------------------------------------------------------
513 Routines that are to be called from outside this file
514 --------------------------------------------------------------------------
515 */
516
517 static alloc_struct alloc_list;
518
519 /* ----------------------------- MNI Header -----------------------------------
520 @NAME : get_total_memory_alloced
521 @INPUT :
522 @OUTPUT :
523 @RETURNS : size_t - the number of bytes allocated
524 @DESCRIPTION: Returns the total amount of memory allocated by the program,
525 : not counting that used by the skip list.
526 @METHOD :
527 @GLOBALS :
528 @CALLS :
529 @CREATED : David MacDonald
530 @MODIFIED :
531 ---------------------------------------------------------------------------- */
532
get_total_memory_alloced(void)533 VIOAPI size_t get_total_memory_alloced( void )
534 {
535 return( alloc_list.total_memory_allocated );
536 }
537
538 static BOOLEAN checking_enabled;
539 static BOOLEAN enabled_initialized = FALSE;
540
541 /* ----------------------------- MNI Header -----------------------------------
542 @NAME : alloc_checking_enabled
543 @INPUT :
544 @OUTPUT :
545 @RETURNS : TRUE if alloc checking is turned on
546 @DESCRIPTION: Checks an environment variable to see if alloc checking is
547 : not disabled.
548 @METHOD :
549 @GLOBALS :
550 @CALLS :
551 @CREATED : David MacDonald
552 @MODIFIED :
553 ---------------------------------------------------------------------------- */
554
alloc_checking_enabled(void)555 VIOAPI BOOLEAN alloc_checking_enabled( void )
556 {
557 #ifdef NO_DEBUG_ALLOC
558 return( FALSE );
559 #else
560 if( !enabled_initialized )
561 {
562 set_alloc_checking( ENV_EXISTS( "DEBUG_ALLOC" ) );
563 }
564
565 return( checking_enabled );
566 #endif
567 }
568
set_alloc_checking(BOOLEAN state)569 VIOAPI void set_alloc_checking( BOOLEAN state )
570 {
571 enabled_initialized = TRUE;
572 checking_enabled = state;
573 }
574
575 /* ----------------------------- MNI Header -----------------------------------
576 @NAME : size_display_enabled
577 @INPUT :
578 @OUTPUT :
579 @RETURNS : TRUE if size displaying is turned on
580 @DESCRIPTION: Checks an environment variable to see if memory size display
581 : is disabled.
582 @METHOD :
583 @GLOBALS :
584 @CALLS :
585 @CREATED : David MacDonald
586 @MODIFIED :
587 ---------------------------------------------------------------------------- */
588
size_display_enabled(void)589 static BOOLEAN size_display_enabled( void )
590 {
591 #ifdef NO_DEBUG_ALLOC
592 return( FALSE );
593 #else
594 static BOOLEAN first = TRUE;
595 static BOOLEAN enabled;
596
597 if( first )
598 {
599 enabled = ENV_EXISTS( "ALLOC_SIZE" );
600 first = FALSE;
601 }
602
603 return( enabled );
604 #endif
605 }
606
607 /* ----------------------------- MNI Header -----------------------------------
608 @NAME : get_stop_sequence_number
609 @INPUT :
610 @OUTPUT :
611 @RETURNS : which allocation number
612 @DESCRIPTION: Returns the number at which allocation should stop. This is
613 used for debugging. For instance, if an error message indicates
614 a problem with the 100'th alloc of the program, then do a
615 SETENV STOP_ALLOC_AT 100 and run the program from the debugger.
616 It will stop at the requested allocation.
617 @METHOD :
618 @GLOBALS :
619 @CALLS :
620 @CREATED : 1993 David MacDonald
621 @MODIFIED :
622 ---------------------------------------------------------------------------- */
623
get_stop_sequence_number(void)624 static int get_stop_sequence_number( void )
625 {
626 static int first = TRUE;
627 static int stop_sequence_number = -1;
628 STRING str;
629
630 if( first )
631 {
632 first = FALSE;
633 str = getenv( "STOP_ALLOC_AT" );
634 if( str == NULL ||
635 sscanf( str, "%d", &stop_sequence_number ) != 1 )
636 stop_sequence_number = -1;
637 }
638
639 return( stop_sequence_number );
640 }
641
642 /* ----------------------------- MNI Header -----------------------------------
643 @NAME : get_current_sequence_number
644 @INPUT :
645 @OUTPUT :
646 @RETURNS : the index of this alloc
647 @DESCRIPTION: Returns the count of how many allocations have been done, so that
648 each allocation can be assigned a value equal to its cardinality
649 in the set of allocations over the life of the program.
650 @METHOD :
651 @GLOBALS :
652 @CALLS :
653 @CREATED : 1993 David MacDonald
654 @MODIFIED :
655 ---------------------------------------------------------------------------- */
656
get_current_sequence_number(void)657 static int get_current_sequence_number( void )
658 {
659 static int current_sequence_number = 0;
660
661 ++current_sequence_number;
662
663 if( current_sequence_number == get_stop_sequence_number() )
664 handle_internal_error( "get_current_sequence_number" );
665
666 return( current_sequence_number );
667 }
668
669 /* ----------------------------- MNI Header -----------------------------------
670 @NAME : record_ptr
671 @INPUT : ptr
672 : n_bytes
673 : source_file
674 : line_number
675 @OUTPUT :
676 @RETURNS :
677 @DESCRIPTION: Records the information about a single allocation in the list.
678 @METHOD :
679 @GLOBALS :
680 @CALLS :
681 @CREATED : David MacDonald
682 @MODIFIED :
683 ---------------------------------------------------------------------------- */
684
record_ptr_alloc_check(void * ptr,size_t n_bytes,STRING source_file,int line_number)685 VIOAPI void record_ptr_alloc_check(
686 void *ptr,
687 size_t n_bytes,
688 STRING source_file,
689 int line_number )
690 {
691 update_struct update_ptrs;
692 skip_entry *entry;
693
694 if( alloc_checking_enabled() )
695 {
696 check_initialized_alloc_list( &alloc_list );
697
698 if( n_bytes == 0 )
699 {
700 print_source_location( source_file, line_number, -1 );
701 print_error( ": Alloc called with zero size.\n" );
702 abort_if_allowed();
703 }
704 else if( ptr == (void *) 0 )
705 {
706 print_source_location( source_file, line_number, -1 );
707 print_error( ": Alloc returned a NIL pointer.\n" );
708 abort_if_allowed();
709 }
710 else
711 {
712 (void) find_pointer_position( &alloc_list, ptr, &update_ptrs );
713
714 if( check_overlap( &alloc_list, &update_ptrs, ptr, n_bytes, &entry))
715 {
716 print_source_location( source_file, line_number, -1 );
717 print_error(
718 ": Alloc returned a pointer overlapping an existing block:\n"
719 );
720 print_source_location( entry->source_file, entry->line_number,
721 entry->sequence_number );
722 print_error( "\n" );
723 abort_if_allowed();
724 }
725 else
726 insert_ptr_in_alloc_list( &alloc_list,
727 &update_ptrs, ptr, n_bytes,
728 source_file, line_number,
729 get_current_sequence_number() );
730 }
731 }
732 }
733
734 /* ----------------------------- MNI Header -----------------------------------
735 @NAME : change_ptr
736 @INPUT : old_ptr
737 : new_ptr
738 : n_bytes
739 : source_file
740 : line_number
741 @OUTPUT :
742 @RETURNS :
743 @DESCRIPTION: Changes the information (mainly the n_bytes) associated with a
744 : given pointer. This function is called from the def_alloc
745 : macros after a realloc().
746 @METHOD :
747 @GLOBALS :
748 @CALLS :
749 @CREATED : David MacDonald
750 @MODIFIED :
751 ---------------------------------------------------------------------------- */
752
change_ptr_alloc_check(void * old_ptr,void * new_ptr,size_t n_bytes,STRING source_file,int line_number)753 VIOAPI void change_ptr_alloc_check(
754 void *old_ptr,
755 void *new_ptr,
756 size_t n_bytes,
757 STRING source_file,
758 int line_number )
759 {
760 STRING orig_source;
761 int orig_line;
762 int sequence_number;
763 skip_entry *entry;
764 update_struct update_ptrs;
765
766 if( alloc_checking_enabled() )
767 {
768 check_initialized_alloc_list( &alloc_list );
769
770 if( n_bytes == 0 )
771 {
772 print_source_location( source_file, line_number, -1 );
773 print_error( ": Realloc called with zero size.\n" );
774 abort_if_allowed();
775 }
776 else if( !remove_ptr_from_alloc_list( &alloc_list, old_ptr,
777 &orig_source, &orig_line, &sequence_number ) )
778 {
779 print_source_location( source_file, line_number, -1 );
780 print_error( ": Tried to realloc a pointer not already alloced.\n");
781 abort_if_allowed();
782 }
783 else
784 {
785 (void) find_pointer_position( &alloc_list, new_ptr, &update_ptrs );
786
787 if( check_overlap( &alloc_list, &update_ptrs, new_ptr, n_bytes,
788 &entry ) )
789 {
790 print_source_location( source_file, line_number, -1 );
791 print_error(
792 ": Realloc returned a pointer overlapping an existing block:\n");
793 print_source_location( entry->source_file, entry->line_number,
794 entry->sequence_number );
795 print_error( "\n" );
796 abort_if_allowed();
797 }
798 else
799 insert_ptr_in_alloc_list( &alloc_list,
800 &update_ptrs, new_ptr, n_bytes,
801 orig_source, orig_line, sequence_number );
802 }
803 }
804 }
805
806 /* ----------------------------- MNI Header -----------------------------------
807 @NAME : unrecord_ptr
808 @INPUT : ptr
809 : source_file
810 : line_number
811 @OUTPUT :
812 @RETURNS : TRUE if ptr was in list
813 @DESCRIPTION: Removes the entry for the given ptr from the list. Called by
814 : the macros during a FREE. Returns TRUE if the pointer was
815 : in the list.
816 @METHOD :
817 @GLOBALS :
818 @CALLS :
819 @CREATED : David MacDonald
820 @MODIFIED :
821 ---------------------------------------------------------------------------- */
822
unrecord_ptr_alloc_check(void * ptr,STRING source_file,int line_number)823 VIOAPI BOOLEAN unrecord_ptr_alloc_check(
824 void *ptr,
825 STRING source_file,
826 int line_number )
827 {
828 BOOLEAN was_previously_alloced;
829 STRING orig_source;
830 int orig_line;
831 int sequence_number;
832
833 was_previously_alloced = TRUE;
834
835 if( alloc_checking_enabled() )
836 {
837 check_initialized_alloc_list( &alloc_list );
838
839 if( ptr == (void *) 0 )
840 {
841 print_source_location( source_file, line_number, -1 );
842 print_error( ": Tried to free a NIL pointer.\n" );
843 abort_if_allowed();
844 was_previously_alloced = FALSE;
845 }
846 else if( !remove_ptr_from_alloc_list( &alloc_list, ptr, &orig_source,
847 &orig_line, &sequence_number ) )
848 {
849 print_source_location( source_file, line_number, -1 );
850 print_error( ": Tried to free a pointer not alloced.\n" );
851 abort_if_allowed();
852 was_previously_alloced = FALSE;
853 }
854 }
855
856 return( was_previously_alloced );
857 }
858
859 /* ----------------------------- MNI Header -----------------------------------
860 @NAME : output_alloc_to_file
861 @INPUT : filename
862 @OUTPUT :
863 @RETURNS :
864 @DESCRIPTION: Outputs a list of all memory allocated to the given file. Usually
865 : done at the end of the program to see if there is any memory that
866 : was orphaned.
867 @METHOD :
868 @GLOBALS :
869 @CALLS :
870 @CREATED : David MacDonald
871 @MODIFIED :
872 ---------------------------------------------------------------------------- */
873
output_alloc_to_file(STRING filename)874 VIOAPI void output_alloc_to_file(
875 STRING filename )
876 {
877 FILE *file;
878 STRING date_str;
879
880 if( alloc_checking_enabled() )
881 {
882 check_initialized_alloc_list( &alloc_list );
883
884 if( memory_still_alloced( &alloc_list ) )
885 {
886 print_error( "\n" );
887 print_error( "\n" );
888 print_error( "A memory leak was found in this program.\n" );
889 if( filename != NULL )
890 print_error(
891 "A description has been recorded in the file %s.\n",
892 filename );
893 print_error(
894 "Please report this file to the author of the program.\n" );
895 print_error( "\n" );
896
897 if( filename != NULL && filename[0] != (char) 0 )
898 file = fopen( filename, "w" );
899 else
900 file = stdout;
901
902 if( file != (FILE *) 0 )
903 {
904 date_str = get_date();
905
906 (void) fprintf( file, "Alloc table at %s\n", date_str );
907
908 delete_string( date_str );
909
910 output_alloc_list( file, &alloc_list );
911
912 if( file != stdout )
913 (void) fclose( file );
914 }
915 }
916 }
917 }
918
919 #ifndef NO_DEBUG_ALLOC
920
print_alloc_source_line(STRING filename,int line_number)921 VIOAPI void print_alloc_source_line(
922 STRING filename,
923 int line_number )
924 {
925 print_error( " Source position: %s:%d\n", filename, line_number );
926 }
927
928 #endif
929