1 /*
2  *   Copyright (C) 1988-1992 Yale University
3  *
4  *   This work is distributed in the hope that it will be useful; you can
5  *   redistribute it and/or modify it under the terms of the
6  *   GNU General Public License as published by the Free Software Foundation;
7  *   either version 2 of the License,
8  *   or any later version, on the following conditions:
9  *
10  *   (a) YALE MAKES NO, AND EXPRESSLY DISCLAIMS
11  *   ALL, REPRESENTATIONS OR WARRANTIES THAT THE MANUFACTURE, USE, PRACTICE,
12  *   SALE OR
13  *   OTHER DISPOSAL OF THE SOFTWARE DOES NOT OR WILL NOT INFRINGE UPON ANY
14  *   PATENT OR
15  *   OTHER RIGHTS NOT VESTED IN YALE.
16  *
17  *   (b) YALE MAKES NO, AND EXPRESSLY DISCLAIMS ALL, REPRESENTATIONS AND
18  *   WARRANTIES
19  *   WHATSOEVER WITH RESPECT TO THE SOFTWARE, EITHER EXPRESS OR IMPLIED,
20  *   INCLUDING,
21  *   BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
22  *   PARTICULAR
23  *   PURPOSE.
24  *
25  *   (c) LICENSEE SHALL MAKE NO STATEMENTS, REPRESENTATION OR WARRANTIES
26  *   WHATSOEVER TO
27  *   ANY THIRD PARTIES THAT ARE INCONSISTENT WITH THE DISCLAIMERS BY YALE IN
28  *   ARTICLE
29  *   (a) AND (b) above.
30  *
31  *   (d) IN NO EVENT SHALL YALE, OR ITS TRUSTEES, DIRECTORS, OFFICERS,
32  *   EMPLOYEES AND
33  *   AFFILIATES BE LIABLE FOR DAMAGES OF ANY KIND, INCLUDING ECONOMIC DAMAGE OR
34  *   INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER YALE SHALL BE
35  *   ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE
36  *   POSSIBILITY OF THE FOREGOING.
37  *
38  */
39 
40 /* -----------------------------------------------------------------
41 FILE:	    okmalloc.c
42 DESCRIPTION:This file contains memory management routines.
43 	    User should always call safe_malloc, safe_free, etc.
44 	    A conditional compile allows the choice between this
45 	    memory manager and system.  Using the memory manager
46 	    helps make the environment similar on all machines.
47 CONTENTS:
48 	    ++++++++++++ HEAP MANAGEMENT ROUTINES ++++++++++++++
49 	    static status_t  heapDispose (ptr)
50 		char_p ptr;
51 	    static status_t  allocateRegion (min_size)
52 		INT min_size;
53 	    static status_t  heapInit (initial_size)
54 		INT initial_size;
55 	    static status_t  heapNew (ptr, req_size)
56 		char_p  *ptr;
57 		INT   req_size;
58 	    +++++++++ END HEAP MANAGEMENT ROUTINES ++++++++++++
59 	      USER  CALLS FOR C RUN TIME LIBRARY
60 	    VOID Ysafe_free(ptr)
61 		char *ptr;
62 	    VOID Ysafe_cfree(ptr)
63 		char *ptr;
64 	    char *Ysafe_malloc(bytes)
65 		long bytes;
66 	    char *Ysafe_calloc(num_entries, bytes)
67 		long num_entries;
68 		long bytes;
69 	    char *Ysafe_realloc(ptr, bytes)
70 		char *ptr;
71 		long bytes;
72 	    INT YgetCurMemUse()
73 	    INT YcheckMemObj(ptr)
74 		char *ptr ;
75 	    INT Yinit_memsize(memsize)
76 		INT memsize ;
77 	    INT YgetListSize(ptr, offsetPtr)
78 		char *ptr ;
79 		char *offsetPtr ;
80 	    YdebugMemory( flag )
81 		BOOL flag ;
82 	    Ypmemerror( s )
83 		char *s ;
84 	    YcheckDebug( where )
85 		INT where ;
86 	    char *Yvector_alloc( lo, hi, size )
87 		INT size, lo, hi ;
88 	    char *Yvector_calloc( lo, hi, size )
89 		INT size, lo, hi ;
90 	    char *Yvector_realloc( array_orig, lo, hi, size )
91 	    VOIDPTR array_orig ;
92 		INT size, lo, hi ;
93 	    VOID Yvector_free( array, lo, size )
94 		VOIDPTR array ;
95 		INT lo, size ;
96 DATE:	    Feb  2, 1988
97 REVISIONS:  Sep 25, 1988 - converted to common utility.
98 	    Feb 22, 1989 - added new memory check for debugger.
99 		    made local function calls static - hide from linker.
100 	    Apr 18, 1989 - added Yinit_memsize for init memory size.
101 	    May  3, 1989 - added Y prefixes.
102 	    Sep 16, 1989 - all debug directed to stderr.
103 	    Dec 21, 1989 - now initialize freed memory to -1 to
104 		catch more bugs.
105 	    Jan 31, 1990 - corrected arg reversal in calloc call.
106 	    Feb  4, 1990 - fixed bug in initializing freed memory.
107 		Also renamed static variables.
108 	    Tue Oct 23 03:33:19 EDT 1990 - fixed for prototypes in
109 		base.h.
110 	    Tue Jan 15 02:06:35 EST 1991 - added vector allocation
111 		routines.
112 	    Thu Jan 24 20:19:46 PST 1991 - added more vector routines.
113 	    Thu Jan 31 15:42:52 EST 1991 - added char * cast to
114 		voidptr use in vector routines.
115 	    Fri Feb 15 15:37:16 EST 1991 - added call to message
116 		system so that silent mode will work.
117 	    Sat May 11 22:53:49 EDT 1991 - added a conditional compile
118 		for HPUX.
119 	    Sat Dec 14 14:33:10 EST 1991 - added YgetMaxMemUse()
120 	    Sun Dec 15 02:30:59 EST 1991 - added the MEM_DEBUG conditional
121 		compile.  We added extra arguments to the alloc routines
122 		so that we could pass the line that the memory was
123 		created.  We now can dump all the allocated memory by
124 		calling Ydump_mem().
125 	    Tue Jan  7 18:03:31 EST 1992 - fixed memory manager
126 		on the MAC.
127 ----------------------------------------------------------------- */
128 
129 #include	<stdio.h>
130 #include	<unistd.h>
131 #include	<signal.h>
132 #include	<errno.h>
133 #include 	<yalecad/base.h>
134 #include 	<yalecad/message.h>
135 
136 #ifdef HPUX
137 #undef		NBPG
138 #include        <machine/parm.h>
139 #endif
140 
141 
142 /* memory errors */
143 #define  heap_error_base   0x40060000
144 #define  heap_bad_block    (heap_error_base + 1)
145 #define  heap_no_mem       (heap_error_base + 2)
146 #define  heap_ok          0
147 
148 #ifdef MEM_DEBUG
149 #include        	<yalecad/file.h>
150 /* -----------------------------------------------------------------
151    These two unusual definitions MEM_DEBUG1 and MEM_DEBUG2 add
152    arguments to memory user routines so that we can pass the file
153    and line number from the preprocessor.
154 ----------------------------------------------------------------- */
155 #define MEM_DEBUG1	,file,line
156 #define MEM_DEBUG2      char *file ; int line ;
157 #define ALLOC_NAME_SIZE 40
158 #else
159 #define MEM_DEBUG1
160 #define MEM_DEBUG2
161 #endif /* MEM_DEBUG */
162 
163 /* conditional compile for the memory manager */
164 /* if MEMORYMAN is not defined use system malloc calloc etc. */
165 
166 #ifdef MEMORYMAN
167 
168 #define systype "bsd4.2"
169 /*
170   *--------------------------------------------------------------
171   * C MEMORY MANAGEMENT SYSTEM
172   *          Description : These Routines replace malloc/calloc
173   *                        & free calls.  AVOID deficiencies in
174   *                        APOLLO heap management routines.
175   *
176   * CODED BY : Bill Swartz
177   *--------------------------------------------------------------
178 */
179 
180 #define  mp_block_cnt      256
181 #define  region_mask       0xFFFF8000
182 #define  region_overhead   8
183 #define  DFL_REGION_SIZE   (4095 * 1024)
184 #define  expected_size     (256  * 1024)
185 #define  waste_allowed     28
186 #define  FOREVER           1
187 
188 #define  block_overhead    (sizeof(header_t) + sizeof(trailer_t))
189 #define  double_word_mask  0xFFFFFFFC
190 
191 #define  char_p            char *
192 
193 typedef  struct {
194             INT              size;
195          }  header_t;
196 
197 typedef  struct {
198             INT              all;
199          }  status_t;
200 
201 typedef  struct block_type {
202             header_t         head;
203             union {
204                struct {
205                   struct block_type   *link;
206                   struct block_type   *back;
207                } zero_case;
208                INT              data;
209             } case_of_two;
210          }  block_t, *block_p;
211 
212 typedef  INT              region_head_t, *region_head_p;
213 
214 typedef  struct {
215             INT             size;
216          }  trailer_t, *trailer_p;
217 
218 typedef  struct {
219             block_t          avail;
220             block_p          alloc_rover;
221             region_head_p    highest_region;
222             INT              cnt_blks;
223             INT              max_blks;
224          }  zone_t;
225 
226 static  zone_t       zoneS ;
227 static status_t      statuS;
228 static BOOL heapNotStartedS = TRUE;
229 static INT totalAllocationS = 0 ;
230 static BOOL debugFlagS = FALSE ;
231 static INT inUseS = 0 ;
232 static INT regionSizeS = DFL_REGION_SIZE ;
233 static INT max_usedS = 0 ;
234 
235 #ifdef MEM_DEBUG
236 
237 /* keep an linked list of allocated memory */
238 typedef struct mem_obj {
239     char name[ALLOC_NAME_SIZE] ;
240     char *ptr_p ;
241     struct mem_obj *next ;
242     struct mem_obj *prev ;
243 } MEMOBJ, *MEMOBJPTR ;
244 
245 static MEMOBJ name_sentinelS ;
246 static MEMOBJPTR name_listS = &name_sentinelS ;
247 
248 #endif /* MEM_DEBUG */
249 
250 
251 /* ++++++++++++++++++ HEAP MANAGEMENT ROUTINES ++++++++++++++ */
252 /* ---------heap_dispose--------- */
heapDispose(ptr)253 static status_t  heapDispose (ptr)
254 char_p        ptr;
255 {
256    status_t     st;
257    trailer_p     tail;
258    block_p       headPtr;
259    block_p       check;
260    block_p       lower;
261    block_p       higher;
262    block_p       temp;
263    long          l ;
264    long          *i ;
265 
266 /*  Begin procedure heap dispose.  */
267 
268    headPtr = (block_p) ((INT) ptr - sizeof(header_t));
269    inUseS += headPtr->head.size ;
270    tail = (trailer_p) ( ((INT)headPtr) - headPtr->head.size - sizeof(trailer_t));
271    if ((headPtr->head.size > 0) || (headPtr->head.size != tail->size)) {
272      st.all = heap_bad_block;
273      return (st);
274    } else if( debugFlagS ) {
275 	/* set the old memory to -1 */
276 	headPtr = (block_p) ((INT) ptr - sizeof(header_t));
277 	/* find number of words; - 2 accounts for header and trailer */
278 	l = ABS( headPtr->head.size ) / sizeof(long) - 2 ;
279 	for(i=(long *) ptr;l>0;i++, l--){
280 	    *i=(long)-1;
281 	}
282    }
283 
284    headPtr->head.size *= -1;
285    tail = (trailer_p) ( ((INT)headPtr) - sizeof(trailer_t));
286    if (tail->size > 0) {
287       check = (block_p) ( ((INT)headPtr) - tail->size);
288       higher = check->case_of_two.zero_case.link;
289       lower = check->case_of_two.zero_case.back;
290       higher->case_of_two.zero_case.back = lower;
291       lower->case_of_two.zero_case.link = higher;
292       check->head.size += headPtr->head.size;
293       headPtr = check;
294    }
295 
296   check = (block_p) ( ((INT)headPtr) + headPtr->head.size);
297   if (check->head.size > 0) {
298       if (zoneS.alloc_rover == (block_p) &(check->head.size)) {
299          zoneS.alloc_rover = (block_p) &(headPtr->head.size);
300       }
301       higher = check->case_of_two.zero_case.link;
302       lower = check->case_of_two.zero_case.back;
303       higher->case_of_two.zero_case.back = lower;
304       lower->case_of_two.zero_case.link = higher;
305       headPtr->head.size += check->head.size;
306    }
307    tail = (trailer_p) ( ((INT)headPtr) + headPtr->head.size - sizeof(trailer_t));
308    tail->size = headPtr->head.size;
309    headPtr->case_of_two.zero_case.link = zoneS.avail.case_of_two.zero_case.link;
310    headPtr->case_of_two.zero_case.back = (block_p) &(zoneS.avail);
311    temp =  (block_p) &(headPtr->head);
312    zoneS.avail.case_of_two.zero_case.link->case_of_two.zero_case.back = temp ;
313    zoneS.avail.case_of_two.zero_case.link = temp ;
314 
315 #ifdef MEM_DEBUG
316     {
317 	MEMOBJPTR mem_p ;
318 	/* this is brain dead for now */
319 	for( mem_p = name_listS->next; mem_p != name_listS; mem_p = mem_p->next ){
320 	    if( mem_p->ptr_p == ptr ){
321 		/* delete this from memory */
322 		mem_p->prev->next = mem_p->next ;
323 		mem_p->next->prev = mem_p->prev ;
324 		heapDispose( mem_p ) ;
325 		break ;
326 	    }
327 	}
328     }
329 #endif /* end MEM_DEBUG */
330 
331    st.all = heap_ok;
332    return (st);
333 }  /*  End of procedure heap dispose.  */
334 
335 
336 /* ---------- Utility Routines ---------- */
337 
allocateRegion(min_size)338 static status_t  allocateRegion (min_size)
339 INT            min_size;
340 {
341 typedef  INT   *tag_p;
342 
343    status_t      st;
344    block_p        head;
345    trailer_p      tail;
346    INT            allocation;
347    INT            pageSize;
348    INT            i;
349    INT            *memory;
350 
351 /*  Begin procedure allocate region.  */
352 #ifndef SYS5
353    pageSize = getpagesize() ;
354 #else /* SYS5 */
355    pageSize = NBPG ;
356 #endif /* SYS5 */
357    if( min_size < expected_size ){
358 	min_size = expected_size ;
359    }
360    allocation = min_size + 2*sizeof(INT);
361    allocation += pageSize - (allocation % pageSize) ;
362    totalAllocationS += allocation ;
363    head = (block_p) sbrk(0) ;
364    sprintf( YmsgG, "Alternate MEMORY MANagement system invoked - allocation:%d bytes\n", allocation ) ;
365    M( MSG, NULL, YmsgG ) ;
366    if( debugFlagS ){
367        fprintf( stderr, "Memory debug switch on\n") ;
368        fprintf( stderr, "old starting memory address:%0x Page size = %d\n",
369 	    head,pageSize) ;
370    }
371    head = (block_p) sbrk(allocation) ;
372    if( debugFlagS ){
373        fprintf( stderr,
374            "new starting memory address:%0x with allocation:%d bytes\n",
375             head, allocation) ;
376        if( !( heapNotStartedS) ){
377 	   fprintf( stderr,
378 	   "current memory request = %d bytes approx. %d pages\n",
379 	       min_size,min_size/pageSize) ;
380 	   fprintf( stderr,
381 	   "total user memory allocated = %d bytes approx. %d pages\n",
382 	        inUseS,inUseS/pageSize) ;
383        }
384        fprintf( stderr,
385        "new memory space = %d pages of %d bytes\n",
386 	    totalAllocationS / pageSize, pageSize) ;
387        fprintf( stderr,"total current allocation = %d\n\n",totalAllocationS ) ;
388    }
389    /* head = (block_p) malloc(allocation) */ ;
390    if ( !(head) || head == (block_p) -1) {
391        st.all = heap_no_mem ;
392        return( st ) ;
393    }
394    if( debugFlagS ){
395        /* initialize all bytes of memory to 1 to catch bugs */
396        memory = (INT *) head ;
397        for( i=0;i<allocation/4;i++){
398 	    memory[i] = -1 ;
399        }
400    }
401 
402    inUseS += allocation - 2*sizeof(INT) ;
403    tail = (trailer_p) ((INT) head + allocation - sizeof(INT));
404    if (zoneS.highest_region != NULL) {
405       if (zoneS.highest_region + ABS(*zoneS.highest_region) == (INT *) head) {
406          *zoneS.highest_region = *zoneS.highest_region - allocation;
407          head = (block_p) ((INT) head - sizeof(INT));
408       } else {
409          zoneS.highest_region = (INT *) head;
410          *zoneS.highest_region = -allocation;
411          head = (block_p) ((INT) head + sizeof(INT));
412          allocation = allocation - 2*sizeof(INT);
413       }
414    } else {
415       zoneS.highest_region = (INT *) head;
416       *zoneS.highest_region = -allocation;
417       head = (block_p) ((INT) head + sizeof(INT));
418       allocation = allocation - 2*sizeof(INT);
419    }
420 
421    tail->size = *zoneS.highest_region;
422    tail = (trailer_p) ((INT) head + allocation - sizeof(INT));
423    head->head.size = tail->size = -allocation;
424    head = (block_p) ((INT) head + sizeof(INT));
425    st = heapDispose (head);
426    zoneS.alloc_rover = zoneS.avail.case_of_two.zero_case.link;
427    st.all = heap_ok;
428    return (st);
429 }  /*  End procedure allocate region.  */
430 
431 
432 /* -------- heap_init -------- */
heapInit(initial_size)433 static status_t  heapInit (initial_size)
434 INT           initial_size;
435 {
436    status_t     st;
437    block_p       block;
438    INT           allocation;
439 
440 /*  Begin procedure heap init.  */
441 
442    /* initialize zone record */
443    zoneS.avail.head.size = 0 ;
444    zoneS.avail.case_of_two.zero_case.link = &(zoneS.avail) ;
445    zoneS.avail.case_of_two.zero_case.back = &(zoneS.avail) ;
446    zoneS.alloc_rover = &(zoneS.avail) ;
447    zoneS.highest_region = NULL ;
448    zoneS.cnt_blks = 0 ;
449    zoneS.max_blks = 0 ;
450 #ifdef MEM_DEBUG
451    name_listS->next = name_listS ;
452    name_listS->prev = name_listS ;
453 #endif /* MEM_DEBUG */
454 
455    if (initial_size > 0) {
456       st = allocateRegion (initial_size);
457       if (st.all != heap_ok){
458          return (st);
459       } else {
460          heapNotStartedS = FALSE;
461       }
462    }
463    st.all = heap_ok;
464    return (st);
465 }  /*  End of procedure heap init.  */
466 
467 
468 /* -------- heap_new --------- */
469 static status_t  heapNew (ptr, req_size MEM_DEBUG1 )
470 char_p        *ptr;
471 INT           req_size;
472 MEM_DEBUG2
473 {
474    status_t       st;
475    INT            excess;
476    INT            allocation;
477    INT            block_size;
478    block_p        new_block;
479    block_p        check;
480    trailer_p      trailer;
481    region_head_p  region;
482 
483 /*  Begin procedure heap new.  */
484    if (req_size <= 0) {
485       *ptr = NULL;
486       st.all = heap_ok;
487       return (st);
488    } else if (heapNotStartedS){
489       heapInit(regionSizeS);
490    }
491    block_size = (req_size + 3 + block_overhead) & double_word_mask;
492    check = zoneS.alloc_rover;
493    do {
494       if (check->head.size < block_size) {
495          check = check->case_of_two.zero_case.link;
496       } else {
497          excess = check->head.size - block_size;
498          zoneS.alloc_rover = check->case_of_two.zero_case.link;
499          if (excess < waste_allowed) {
500             check->case_of_two.zero_case.back->case_of_two.zero_case.link =
501 	        check->case_of_two.zero_case.link;
502             check->case_of_two.zero_case.link->case_of_two.zero_case.back =
503 		check->case_of_two.zero_case.back;
504             block_size = check->head.size;
505          } else {
506             check->head.size = excess;
507             trailer = (trailer_p) ((INT) check + excess - sizeof(trailer_t));
508             trailer->size = excess;
509             check = (block_p) ((INT) check + excess);
510          }
511          check->head.size = -block_size;
512          trailer = (trailer_p) ((INT) check + block_size - sizeof(trailer_t));
513          trailer->size = -block_size;
514          *ptr = (char_p) &(check->case_of_two.data);
515 #ifdef MEM_DEBUG
516 	 {
517 	    INT len ;
518 	    char alloc_name[BUFSIZ] ;
519 	    MEMOBJPTR name_data ;
520 	    if( file ){
521 		sprintf( alloc_name, "%s:%d", file, line ) ;
522 		len = strlen( alloc_name ) ;
523 		if( len < ALLOC_NAME_SIZE ){
524 		    /* allocate space for record info but don't put in tree */
525 		    statuS = heapNew (&name_data, sizeof(MEMOBJ), NULL, 0 ) ;
526 		    if (statuS.all!=heap_ok){
527 		       errno = statuS.all ;
528 		       kill(getpid(),SIGUSR1);
529 		    }
530 		    strcpy( name_data->name, alloc_name ) ;
531 		    name_data->ptr_p = *ptr ;
532 		    name_data->next = name_listS->next ;
533 		    name_listS->next->prev = name_data ;
534 		    name_listS->next = name_data ;
535 		    name_data->prev = name_listS ;
536 		} else {
537 		    fprintf( stderr,
538 			"Alloc name:%s too long to store\n",alloc_name ) ;
539 		}
540 	    }
541 	 }
542 #endif /* MEM_DEBUG */
543 	 inUseS += block_size ;
544 	 if( inUseS > max_usedS ) max_usedS = inUseS ;
545          st.all = heap_ok;
546          return (st);
547       }
548       if (check == zoneS.alloc_rover) {
549          st = allocateRegion (block_size);
550 	 if( inUseS > max_usedS ) max_usedS = inUseS ;
551          if (st.all != heap_ok)
552             return (st);
553          check = zoneS.alloc_rover;
554       }
555    } while (FOREVER);
556 }  /*  End procedure heap new.  */
557 
Ydump_mem()558 VOID Ydump_mem()
559 {
560 #ifdef MEM_DEBUG
561     FILE *fp ;
562     MEMOBJPTR	mem_p ;
563     static INT dump_noL = 0 ;
564     char filename[LRECL] ;
565     INT sum_allocated ;
566     INT size ;
567 
568     sum_allocated = 0 ;
569     sprintf( filename, "mem.data.%d", ++dump_noL ) ;
570     fp = TWOPEN( filename, "w", ABORT ) ;
571     fprintf( fp, "Address:amount_allocated file:line_number\n" ) ;
572     for( mem_p = name_listS->next; mem_p != name_listS; mem_p = mem_p->next ){
573 	size = YcheckMemObj(mem_p->ptr_p) ;
574 	fprintf( fp, "%x:%d %s\n", mem_p->ptr_p, size, mem_p->name ) ;
575 	sum_allocated += size ;
576     }
577     fprintf( fp, "-----------------------------------------------------------\n");
578     fprintf( fp, "Total allocation:%d\n", sum_allocated ) ;
579 
580     TWCLOSE( fp ) ;
581 #else /* MEM_DEBUG */
582     fprintf( stderr, "Ydump_mem() is not available. Use libycad.mem-d.a\n" ) ;
583 #endif /* MEM_DEBUG */
584 } /* end Ydump_mem() */
585 
586 
587 /* ++++++++++++++++++ END HEAP MANAGEMENT ROUTINES ++++++++++++++ */
588 
589 /*  SUBSTITION CALLS FOR C RUN TIME LIBRARY */
590 
591 VOID Ysafe_free(ptr MEM_DEBUG1 )
592 VOIDPTR ptr;
593 MEM_DEBUG2
594 {
595     if( !( ptr ) ){
596 	fprintf( stderr,
597 	    "WARNING[safe_free]:pointer = nil.  Ignoring safe_free.\n") ;
598 	return ;
599     }
600 
601     statuS = heapDispose (ptr);
602     if (statuS.all != heap_ok){
603 	errno = statuS.all ;
604 	kill(getpid(),SIGUSR1);
605     }
606 }
607 
608 VOID Ysafe_cfree(ptr MEM_DEBUG1 )
609 VOIDPTR ptr;
610 MEM_DEBUG2
611 {
612     if( !( ptr ) ){
613 	fprintf(stderr,
614 	"WARNING[safe_cfree]:pointer = nil.  Ignoring safe_cfree.\n") ;
615 	return ;
616     }
617 
618     statuS = heapDispose (ptr);
619     if (statuS.all!=heap_ok){
620 	errno = statuS.all ;
621 	kill(getpid(),SIGUSR1);
622     }
623 }
624 
625 
626 char *Ysafe_malloc(bytes MEM_DEBUG1 )
627 INT bytes;
628 MEM_DEBUG2
629 {
630    char *ptr;
631    char *i;
632    if (bytes<5) {
633       bytes = 8;
634    }
635    statuS = heapNew (&ptr, bytes MEM_DEBUG1 );
636    if (statuS.all!=heap_ok){
637        errno = statuS.all ;
638        kill(getpid(),SIGUSR1);
639    }
640    return(ptr);
641 }
642 
643 char *Ysafe_calloc(num_entries, bytes MEM_DEBUG1 )
644 INT num_entries;
645 INT bytes;
646 MEM_DEBUG2
647 {
648    char *ptr;
649    long *i;
650    long k,l;
651 
652    k = bytes*num_entries;
653    if (k<5) {
654       k = 8;
655    }
656    statuS = heapNew (&ptr, k MEM_DEBUG1 );
657    if (statuS.all!=heap_ok){
658        errno = statuS.all ;
659        kill(getpid(),SIGUSR1);
660    }
661    l = (k+3)>>2;
662    for(i=(long *)ptr;l>0;i++, l--){
663       *i=(long)0;
664    }
665    return(ptr);
666 }
667 
668 char *Ysafe_realloc(ptr, bytes MEM_DEBUG1 )
669 VOIDPTR ptr;
670 INT bytes;
671 MEM_DEBUG2
672 {
673 
674    char               *ptr2;
675    INT                oldSize;
676    INT                i;
677    block_p            headPtr;
678    trailer_p          tail;
679 
680    /* allocate new memory */
681    ptr2 = Ysafe_malloc(bytes MEM_DEBUG1 );
682 
683    /* get current size of ptr */
684    headPtr = (block_p) ((INT) ptr - sizeof(header_t));
685    tail = (trailer_p) ( ((INT)headPtr) - headPtr->head.size
686 	   - sizeof(trailer_t));
687    if ((headPtr->head.size > 0) || (headPtr->head.size != tail->size)) {
688        errno = heap_bad_block ;
689        kill(getpid(),SIGUSR1);
690    }
691    /* copy only the smaller amount of two blocks */
692    oldSize = - (headPtr->head.size) ;
693    if( oldSize < bytes ){
694       bytes = oldSize ;
695    }
696 
697    for (i=0; i<bytes; i++){
698        ptr2[i] = ((char *) ptr)[i];
699    }
700 
701 
702    Ysafe_free(ptr MEM_DEBUG1 );
703 
704    return(ptr2);
705 }
706 
Yinit_memsize(memsize)707 VOID Yinit_memsize( memsize )
708 INT memsize ;
709 {
710     regionSizeS = memsize ;
711 } /* end Yinit_memsize */
712 
713 /* getCurMemUse - returns the current allocated memory by user */
YgetCurMemUse()714 INT YgetCurMemUse()
715 {
716     return(inUseS) ;
717 }
718 
719 /* getMaxMemUse - returns the maximum allocated memory by user */
YgetMaxMemUse()720 INT YgetMaxMemUse()
721 {
722     return(max_usedS) ;
723 }
724 
725 /* checkMemObj(ptr) - returns the size of the object pointed to */
726 /* returns size in bytes.  returns -1 if invalid object */
YcheckMemObj(ptr)727 INT YcheckMemObj(ptr)
728 char *ptr ;
729 {
730    block_p            headPtr;
731    trailer_p          tail;
732 
733    /* get current size of ptr */
734    headPtr = (block_p) ((INT) ptr - sizeof(header_t));
735    tail = (trailer_p) ( ((INT)headPtr) - headPtr->head.size
736 	   - sizeof(trailer_t));
737    if ((headPtr->head.size > 0) || (headPtr->head.size != tail->size)) {
738       return(-1) ;
739    }
740    return(-headPtr->head.size - block_overhead) ;
741 } /* end checkMemObj */
742 
743 /* checkDebug call checkMemObj so it can be used in debugger */
YcheckDebug(where)744 INT YcheckDebug( where )
745 VOIDPTR where ; /* must be integer to work in dbx */
746 {
747     INT size ;
748 
749     if( (size = YcheckMemObj( (char *) where )) == -1 ){
750 	fprintf( stderr, "Memory has been damaged\n" ) ;
751 	return( 0 ) ;
752     } else {
753 	return( size ) ;
754     }
755 } /* end checkDebug */
756 
757 /* getListSize(ptr,offset) - returns the size of a linked-list */
758 /* returns size in bytes.  returns -1 if invalid object */
759 /* example.  getListSize(netPtr,&(netPtr->next) ) ;  */
YgetListSize(ptr,offsetPtr)760 INT YgetListSize(ptr, offsetPtr)
761 char *ptr ;     /* pointer to beginning of list structure */
762 char *offsetPtr ;  /* pointer to "next" field within structure */
763 {
764    block_p            headPtr;
765    trailer_p          tail;
766    INT		      recordCount = 0 ;
767    INT		      memInUse = 0 ;
768    INT		      offset ;
769    INT		      limit ;    /* max number of records */
770    INT                *intPtr ;
771    INT                temp ;
772 
773    /* first calculate offset of next field */
774    offset = offsetPtr - ptr ;
775 
776    /* calculate limit to detect circular link list */
777    /* the max number of records = MaxMemory/sizeof(record)
778    /* need current size of ptr for calculation */
779    headPtr = (block_p) ((INT) ptr - sizeof(header_t));
780    tail = (trailer_p) ( ((INT)headPtr) - headPtr->head.size
781       - sizeof(trailer_t));
782    if ((headPtr->head.size > 0) || (headPtr->head.size != tail->size)) {
783        return(-1) ;
784    }
785    if( headPtr->head.size ){
786        limit =  - totalAllocationS / headPtr->head.size ;
787    } else {
788       return(-1) ;
789    }
790 
791    while( ptr ) {   /* perform check while pointer is not null */
792 
793        headPtr = (block_p) ((INT) ptr - sizeof(header_t));
794        tail = (trailer_p) ( ((INT)headPtr) - headPtr->head.size
795              - sizeof(trailer_t));
796        if ((headPtr->head.size > 0) || (headPtr->head.size != tail->size)) {
797 	    if( debugFlagS ){
798 	       fprintf( stderr, "ERROR[getListSize]:record has corrupted data\n") ;
799             }
800             return(-1) ;
801        }
802        memInUse += - headPtr->head.size ;
803        /* check for circular linked list */
804        if( recordCount > limit) {
805 	  fprintf( stderr, "Detected a circular linked list\n") ;
806           return(-1) ;
807        }
808 
809        /* update pointer */
810        /* calculate addresss of next field */
811        intPtr = (INT *) (ptr + offset) ;
812        /* next line does indirect addressing - contents of */
813        /* field is put in temp.  Note we use char point but */
814        /* we need all four bytes of the next field for new pointer */
815        temp = *intPtr ;
816        ptr = (char *) temp ;
817        recordCount++ ;
818     }
819     return(memInUse) ;
820 }
821 
822 /* debugMemory - turns on memory check debug messages and */
823 /* memory to all 1's to detect access violations. */
YdebugMemory(flag)824 VOID YdebugMemory( flag )
825 BOOL flag ;
826 {
827     debugFlagS = flag ;
828 }
829 
830 /*
831   *--------------------------------------------------------------
832   * END OF C MEMORY MANAGEMENT SYSTEM
833   *--------------------------------------------------------------
834 */
835 
836 #else
837 
838 /*
839   *--------------------------------------------------------------
840   * BEGIN NORMAL C MEMORY MANAGEMENT SYSTEM
841   *--------------------------------------------------------------
842 */
843 
844 /* use standard calls to malloc, calloc, etc */
845 
Ysafe_malloc(size)846 char *Ysafe_malloc(size)
847 INT size;
848 {
849     char *p;
850 
851     /*extern char *malloc() ;*/
852 
853     if ((p = malloc(size)) == (char *) 0) {
854         errno = heap_no_mem ;
855         kill(getpid(),SIGUSR1);
856     }
857     return p;
858 }
859 
860 
Ysafe_realloc(obj,size)861 char *Ysafe_realloc(obj, size)
862 VOIDPTR obj;
863 INT size;
864 {
865     char *p;
866 
867     /* extern char *realloc() ;*/
868 
869     if ((p = realloc(obj, size)) == (char *) 0) {
870         errno = heap_no_mem ;
871         kill(getpid(),SIGUSR1);
872     }
873     return p;
874 }
875 
876 
Ysafe_calloc(num,size)877 char *Ysafe_calloc(num, size)
878 INT size, num;
879 {
880     char *p;
881 
882     /*extern char *calloc() ;*/
883 
884     if ((p = calloc(num,size)) == (char *) 0) {
885         errno = heap_no_mem ;
886         kill(getpid(),SIGUSR1);
887     }
888     return p;
889 }
890 /* when not testing memory just call system free */
Ysafe_free(ptr)891 VOID Ysafe_free(ptr)
892 VOIDPTR ptr;
893 {
894     free(ptr);
895     return;
896 }
897 
Ysafe_cfree(ptr)898 VOID Ysafe_cfree(ptr)
899 VOIDPTR ptr;
900 {
901     free(ptr);
902     return;
903 }
904 
905 /* ***********DUMMY ROUTINES TO RESOLVE GLOBALS **************** */
906 /* see above for normal use */
YgetCurMemUse()907 INT YgetCurMemUse()
908 {
909     return(0) ;
910 }
911 
YgetMaxMemUse()912 INT YgetMaxMemUse()
913 {
914     return(0) ;
915 }
916 
YcheckMemObj(ptr)917 INT YcheckMemObj(ptr)
918 char *ptr ;
919 {
920    return(0) ;
921 }
922 
YgetListSize(ptr,offsetPtr)923 INT YgetListSize(ptr, offsetPtr)
924 char *ptr ;     /* pointer to beginning of list structure */
925 char *offsetPtr ;  /* pointer to "next" field within structure */
926 {
927     return(0) ;
928 }
929 
YdebugMemory(flag)930 VOID YdebugMemory( flag )
931 INT flag ;
932 {
933     return ;
934 }
935 
YcheckDebug(where)936 INT YcheckDebug( where )
937 VOIDPTR where ;
938 {
939     return ( INT_MAX ) ;
940 } /* end checkDebug */
941 
Yinit_memsize(memsize)942 VOID Yinit_memsize( memsize )
943 INT memsize ;
944 {
945     return ;
946 } /* end Yinit_memsize */
947 
Ydump_mem()948 VOID Ydump_mem()
949 {
950 } /* end Ydump_mem() */
951 /*
952   *--------------------------------------------------------------
953   * END NORMAL C MEMORY MANAGEMENT SYSTEM
954   *--------------------------------------------------------------
955 */
956 #endif
957 
958 /* print memory error in the same style as perror and psignal */
Ypmemerror(s)959 VOID Ypmemerror( s )
960 char *s ;
961 {
962     /* first print user message if available */
963     if( s ){
964 	fprintf( stderr, "%s:", s ) ;
965     }
966     switch(errno){
967 	case heap_ok:
968 	   fprintf(stderr,
969 	   "Memory ok - Problem in memory management logic.\n" ) ;
970 	   break;
971 	case heap_bad_block:
972 	   fprintf(stderr,
973 	   "Memory block was found to be corrupted.\n" ) ;
974 	   break;
975 	case heap_no_mem:
976 	   fprintf(stderr,
977 	   "No memory available to allocate.\n" ) ;
978 	   break;
979 	default:
980 	   fprintf(stderr,
981 	   "Error = %0x Unrecognized error code.\n",errno ) ;
982     }
983 } /* end Ypmemerror */
984 
985 /* *******  memory convenience functions  ******* */
986 /* ALLOCATE an array [lo..hi] of the given size not initialized */
987 char *Yvector_alloc( lo, hi, size MEM_DEBUG1 )
988 INT size, lo, hi ;
989 MEM_DEBUG2
990 {
991     char *array_return ;
992 
993     array_return = (char *) Ysafe_malloc((unsigned) (hi-lo+1)*size MEM_DEBUG1 ) ;
994     if( array_return ){
995 	return( array_return - size * lo ) ;
996     }
997     return( NIL(char *) ) ;
998 
999 } /* end Yvector_alloc */
1000 
1001 /* ALLOCATE an array [lo..hi] of the given size initialized to zero */
1002 char *Yvector_calloc( lo, hi, size MEM_DEBUG1 )
1003 INT size, lo, hi ;
1004 MEM_DEBUG2
1005 {
1006     char *array_return ;
1007 
1008     array_return = (char *) Ysafe_calloc((unsigned) (hi-lo+1),size MEM_DEBUG1 ) ;
1009     if( array_return ){
1010 	return( array_return - size * lo ) ;
1011     }
1012     return( NIL(char *) ) ;
1013 
1014 } /* end Yvector_calloc */
1015 
1016 /* REALLOCATE an array [lo..hi] of the given size no initialization */
1017 char *Yvector_realloc( array_orig, lo, hi, size MEM_DEBUG1 )
1018 VOIDPTR array_orig ;
1019 INT size, lo, hi ;
1020 MEM_DEBUG2
1021 {
1022     char *adj_array ;          /* put back the offset */
1023     char *array_return ;       /* the new offset */
1024 
1025     adj_array = ((char *) array_orig) + lo * size ;
1026     array_return = (char *)
1027 	Ysafe_realloc( adj_array, (unsigned) (hi-lo+1)*size MEM_DEBUG1 ) ;
1028     if( array_return ){
1029 	return( array_return - size * lo ) ;
1030     }
1031     return( NIL(char *) ) ;
1032 
1033 } /* end Yvector_realloc */
1034 
1035 VOID Yvector_free( array, lo, size MEM_DEBUG1 )
1036 VOIDPTR array ;
1037 INT lo, size ;
1038 MEM_DEBUG2
1039 {
1040     Ysafe_free( ((char *)array) + lo * size MEM_DEBUG1 ) ;
1041 } /* end Yvector_free */
1042 
1043 /* ************************* TEST ROUTINES ******************************** */
1044 #ifdef TEST
1045 
1046 typedef struct {
1047     INT bogus_dude ;
1048     DOUBLE narly ;
1049     char *awesome ;
1050 } MEMDATA, *MEMDATAPTR ;
1051 
main()1052 main()
1053 {
1054     MEMDATAPTR array ;
1055     MEMDATAPTR vector ;
1056     char *string, *Ystrclone() ;
1057 
1058     YdebugMemory( TRUE ) ;
1059     Yinit_memsize( 1024 ) ;
1060 
1061     /* allocate an array 0..9 */
1062     array = YMALLOC( 10, MEMDATA ) ;
1063     fprintf( stderr, "Memory size :%d\n", YgetCurMemUse() ) ;
1064     /* allocate an array 1..10 */
1065     vector = YVECTOR_MALLOC( 1, 10, MEMDATA ) ;
1066     fprintf( stderr, "Memory size :%d\n", YgetCurMemUse() ) ;
1067     /* clone this string */
1068     string = Ystrclone( "Droog" ) ;
1069     fprintf( stderr, "Memory size :%d\n", YgetCurMemUse() ) ;
1070     /* look at mem.data at this point */
1071     Ydump_mem() ;
1072     /* free all the memory */
1073     YFREE( array ) ;
1074     YFREE( string ) ;
1075     YVECTOR_FREE( vector, 1 ) ;
1076     fprintf( stderr, "Memory size :%d\n", YgetCurMemUse() ) ;
1077     fprintf( stderr, "Memory max size :%d\n", YgetMaxMemUse() ) ;
1078     Ydump_mem() ;
1079 
1080     exit(0) ;
1081 
1082 }/* end main() */
1083 
1084 #endif /* TEST */
1085 
1086