1    | /***************************************
2    |   $Header: /home/amb/cxref/src/RCS/memory.c 1.13 2004/06/19 19:03:13 amb Exp $
3    | 
4    |   C Cross Referencing & Documentation tool. Version 1.6.
5    | 
6    |   Memory management functions
7    |   ******************/ /******************
8    |   Written by Andrew M. Bishop
9    | 
10   |   This file Copyright 1995,96,97,2004 Andrew M. Bishop
11   |   It may be distributed under the GNU Public License, version 2, or
12   |   any higher version.  See section COPYING of the GNU Public license
13   |   for conditions under which this file may be redistributed.
14   |   ***************************************/
15   | 
16   | /*+ The amount of debugging, non-zero for totals, 2 for logging, 4 for printing each call. +*/
17   | #define DEBUG 0
18   | 
19   | /* The configure output */
20   | 
21   | #include "autoconfig.h"
22   | 
23   | #include <stdio.h>
24   | #include <stdlib.h>
25   | #include <string.h>
26   | 
27   | #ifdef __STDC__
28   | #include <stdarg.h>
29   | #else
30   | #include <varargs.h>
31   | #endif
32   | 
33   | #include <memory.h>
34   | #include "memory.h"
35   | 
36   | /*+ A private memory heap is used to reduce the number of malloc calls that are made, the Heap type is a pointer to this. +*/
37   | typedef struct _Heap *Heap;
38   | 
39   | /*+ A structure containing all of the information about the private heap in a linked list. +*/
40   | struct _Heap
41   | {
42   |  char* mem;                             /*+ The memory that is private to the heap. +*/
43   |  Heap next;                             /*+ The next Heap structure. +*/
44   | };
45   | 
46   | /*+ Local variable to control the usage of the private heap; +*/
47   | static Heap first=NULL;                 /*+ the first segment of memory on the private heap. +*/
48   | static int heap_left=0;                 /*+ the amount of space left in the current heap segment. +*/
49   | 
50   | static char* get_space(unsigned int l);
51   | static Heap add_to_heap(unsigned int l);
52   | 
53   | #if DEBUG&2
54   | /*+ Variable used for debugging, not a good thing to do. what if more than 16384 mallocs? +*/
55   | static void* addresses[16384];
56   | static char* files[16384];
57   | static int   lines[16384];
58   | #endif
59   | #if DEBUG
60   | /*+ Variable used for debugging. +*/
61   | static int malloc_count=0;
62   | static int realloc_count=0;
63   | static int free_count=0;
64   | #endif
65   | 
66   | 
67   | /*++++++++++++++++++++++++++++++++++++++
68   |   A replacement malloc() function.
69   | 
70   |   void* SafeMalloc Returns the address.
71   | 
72   |   unsigned int size The size of the memory to allocate.
73   | 
74   |   char* file The file that the function is called from.
75   | 
76   |   int line The line number that the function is called from.
77   |   ++++++++++++++++++++++++++++++++++++++*/
78   | 
79   | void* SafeMalloc(unsigned int size,char* file,int line)
80   | {
81   |  void* rptr=malloc(size);
82   | 
83   | #if DEBUG&4
84   |  printf("$$Malloc #%5d of %4d bytes at %08lx (%s:%3d)\n",malloc_count+1,size,(long)rptr,file,line);
85   | #endif
86   | #if DEBUG&2
87   |  if(malloc_count==(sizeof(addresses)/sizeof(addresses[0])))
88   |    {fprintf(stderr,"$$Too many Mallocs to log, edit memory.c\n");exit(3);}
89   |  addresses[malloc_count]=(void*)rptr;
90   |  files[malloc_count]=file;
91   |  lines[malloc_count]=line;
92   | #endif
93   | #if DEBUG
94   |  malloc_count++;
95   |  if(!rptr) printf("$$Warning Malloc() returning NULL (%s:%3d)\n",file,line);
96   | #endif
97   | #if !DEBUG
98   |  if(!rptr) printf("Warning Malloc() returning NULL (%s:%3d)\n",file,line);
99   | #endif
100  | 
101  |  return(rptr);
102  | }
103  | 
104  | 
105  | /*++++++++++++++++++++++++++++++++++++++
106  |   A replacement calloc() function.
107  | 
108  |   void* SafeCalloc Returns the address.
109  | 
110  |   unsigned int n The number of items to allocate.
111  | 
112  |   unsigned int size The size of the memory to allocate.
113  | 
114  |   char* file The file that the function is called from.
115  | 
116  |   int line The line number that the function is called from.
117  |   ++++++++++++++++++++++++++++++++++++++*/
118  | 
119  | void* SafeCalloc(unsigned int n,unsigned int size,char* file,int line)
120  | {
121  |  void* rptr=calloc(n,size);
122  | 
123  | #if DEBUG&4
124  |  printf("$$Calloc #%5d of %4d bytes at %08lx (%s:%3d)\n",malloc_count+1,size,(long)rptr,file,line);
125  | #endif
126  | #if DEBUG&2
127  |  if(malloc_count==(sizeof(addresses)/sizeof(addresses[0])))
128  |    {fprintf(stderr,"$$Too many Mallocs to log, edit memory.c\n");exit(3);}
129  |  addresses[malloc_count]=(void*)rptr;
130  |  files[malloc_count]=file;
131  |  lines[malloc_count]=line;
132  | #endif
133  | #if DEBUG
134  |  malloc_count++;
135  |  if(!rptr) printf("$$Warning Calloc() returning NULL (%s:%3d)\n",file,line);
136  | #endif
137  | #if !DEBUG
138  |  if(!rptr) printf("Warning Calloc() returning NULL (%s:%3d)\n",file,line);
139  | #endif
140  | 
141  |  return(rptr);
142  | }
143  | 
144  | 
145  | /*++++++++++++++++++++++++++++++++++++++
146  |   A replacement realloc() function.
147  | 
148  |   void* SafeRealloc Returns the address.
149  | 
150  |   void* ptr The old pointer.
151  | 
152  |   unsigned int size The size of the new memory to allocate.
153  | 
154  |   char* file The file that the function is called from.
155  | 
156  |   int line The line number that the function is called from.
157  |   ++++++++++++++++++++++++++++++++++++++*/
158  | 
159  | void* SafeRealloc(void* ptr,unsigned int size,char* file,int line)
160  | {
161  |  void* rptr=realloc(ptr,size);
162  | 
163  | #if DEBUG&4
164  |  printf("$$Realloc #%4d of %4d bytes at %08lx (old %08lx) (%s:%3d)\n",realloc_count+1,size,(long)rptr,(long)ptr,file,line);
165  | #endif
166  | #if DEBUG&2
167  |  {
168  |   int i;
169  |   for(i=0;i<malloc_count;i++)
170  |      if(addresses[i]==(void*)ptr)
171  |        {addresses[i]=rptr;break;}
172  |   if(i==malloc_count)
173  |      printf("$$Realloc() called for a non Malloced pointer %08lx (%s:%3d)\n",(long)ptr,file,line);
174  |  }
175  | #endif
176  | #if DEBUG
177  |  realloc_count++;
178  |  if(!rptr) printf("$$Warning Realloc() returning NULL (%s:%3d)\n",file,line);
179  | #endif
180  | #if !DEBUG
181  |  if(!rptr) printf("Warning Realloc() returning NULL (%s:%3d)\n",file,line);
182  | #endif
183  | 
184  |  return(rptr);
185  | }
186  | 
187  | 
188  | /*++++++++++++++++++++++++++++++++++++++
189  |   A replacement free() function.
190  | 
191  |   void* ptr The pointer that is to be freed up.
192  | 
193  |   char* file The file that the function is called from.
194  | 
195  |   int line The line number that the function is called from.
196  |   ++++++++++++++++++++++++++++++++++++++*/
197  | 
198  | void SafeFree(void* ptr,char* file,int line)
199  | {
200  | #if DEBUG&4
201  |  printf("$$Free #%5d at %08lx (%s:%3d)\n",free_count+1,(long)ptr,file,line);
202  | #endif
203  | #if DEBUG&2
204  |  {
205  |   int i;
206  |   for(i=0;i<malloc_count;i++)
207  |      if(addresses[i]==(void*)ptr)
208  |        {addresses[i]=(void*)1;break;} 
209  |   if(i==malloc_count)
210  |      printf("$$Free() called for a non Malloced pointer %08lx (%s:%3d)\n",(long)ptr,file,line);
211  |  }
212  | #endif
213  | #if DEBUG
214  |  free_count++;
215  |  if(!ptr) printf("$$Calling Free() on NULL (%s:%3d)\n",file,line);
216  |  else
217  | #endif
218  | #if !DEBUG
219  |  if(!ptr) printf("Calling Free() on NULL (%s:%3d)\n",file,line);
220  |  else
221  | #endif
222  | 
223  |  free(ptr);
224  | }
225  | 
226  | 
227  | /*++++++++++++++++++++++++++++++++++++++
228  |   A function to copy a string on the public global heap.
229  | 
230  |   char* SafeMallocString Returns the copy of the string.
231  | 
232  |   char* x The string to be copied.
233  | 
234  |   char* file The file that the function is called from.
235  | 
236  |   int line The line number that the function is called from.
237  |   ++++++++++++++++++++++++++++++++++++++*/
238  | 
239  | char* SafeMallocString(char* x,char* file,int line)
240  | {
241  |  char* t=NULL;
242  | 
243  |  if(x)
244  |    {
245  |     t=(char*)SafeMalloc(strlen(x)+1,file,line);
246  |     strcpy(t,x);
247  |    }
248  | 
249  |  return(t);
250  | }
251  | 
252  | 
253  | /*++++++++++++++++++++++++++++++++++++++
254  |   A function to copy a string on the local private memory heap.
255  | 
256  |   char* CopyString Returns the copy of the string.
257  | 
258  |   char* x The string to be copied.
259  |   ++++++++++++++++++++++++++++++++++++++*/
260  | 
261  | char* CopyString(char* x)
262  | {
263  |  char* t=NULL;
264  | 
265  |  if(x)
266  |    {
267  |     t=get_space(strlen(x)+1);
268  |     strcpy(t,x);
269  |    }
270  | 
271  |  return(t);
272  | }
273  | 
274  | 
275  | /*++++++++++++++++++++++++++++++++++++++
276  |   A function to concatenate a number of strings.
277  | 
278  |   char* ConcatStrings Returns the a pointer to the new string.
279  | 
280  |   int n The number of strings
281  | 
282  |   char* s The first string.
283  | 
284  |   ... The other strings, 'n' including 's'.
285  | 
286  |   Any of the strings that are inputs can be NULL, in this case they are quietly ignored.
287  |   ++++++++++++++++++++++++++++++++++++++*/
288  | 
289  | char* ConcatStrings(int n,char* s, ...)
290  | {
291  |  char* t=NULL,*str;
292  |  unsigned int l=0;
293  |  int i;
294  |  va_list ap;
295  | 
296  | #ifdef __STDC__
297  |  va_start(ap,s);
298  | #else
299  |  va_start(ap);
300  | #endif
301  | 
302  |  for(i=0;i<n;i++)
303  |    {
304  |     if(i)
305  |        str=va_arg(ap, char *);
306  |     else
307  |        str=s;
308  | 
309  |     if(str)
310  |        l+=strlen(str);
311  |    }
312  | 
313  |  va_end(ap);
314  | 
315  |  if(l)
316  |    {
317  |     t=get_space(l+1); t[0]=0;
318  | 
319  | #ifdef __STDC__
320  |     va_start(ap,s);
321  | #else
322  |     va_start(ap);
323  | #endif
324  | 
325  |     for(i=0;i<n;i++)
326  |       {
327  |        if(i)
328  |           str=va_arg(ap, char *);
329  |        else
330  |           str=s;
331  | 
332  |        if(str)
333  |           strcat(t,str);
334  |       }
335  | 
336  |     va_end(ap);
337  |    }
338  | 
339  |  return(t);
340  | }
341  | 
342  | 
343  | /*++++++++++++++++++++++++++++++++++++++
344  |   Prints out the number of mallocs / reallocs and frees.
345  |   ++++++++++++++++++++++++++++++++++++++*/
346  | 
347  | void PrintMemoryStatistics(void)
348  | {
349  | #if DEBUG
350  |  printf("\n"
351  |         "$$Memory usage : %5d Malloc()/Calloc() calls\n"
352  |         "$$               %5d Realloc() calls\n"
353  |         "$$               %5d Free() calls\n"
354  |         "$$               %5d Net calls (Malloc-Free)\n",
355  |         malloc_count,realloc_count,free_count,malloc_count-free_count);
356  | #endif
357  | 
358  | #if DEBUG&2
359  |  {
360  |   int i;
361  |   for(i=0;i<malloc_count;i++)
362  |      if(addresses[i]!=(void*)1)
363  |         printf("$$Malloc #%5d at address %08lx is not freed (%s:%3d) = '%s'\n",i+1,(long)addresses[i],files[i],lines[i],(char*)addresses[i]);
364  |  }
365  | #endif
366  | }
367  | 
368  | 
369  | /*++++++++++++++++++++++++++++++++++++++
370  |   Tidies up the local heap of memory.
371  |   ++++++++++++++++++++++++++++++++++++++*/
372  | 
373  | void TidyMemory(void)
374  | {
375  |  if(first)
376  |    {
377  |     Heap h=first,n;
378  |     do
379  |       {
380  |        n=h->next;
381  |        Free(h->mem);
382  |        Free(h);
383  |        h=n;
384  |       }
385  |     while(h);
386  |    }
387  | 
388  |  first=NULL;
389  |  heap_left=0;
390  | }
391  | 
392  | /*+ The size of each of the heap allocations +*/
393  | #define HEAP_INC 8192
394  | 
395  | /*+ The size of a string that is large enough to have it's own mallocation. +*/
396  | #define SMALL_STRING 256
397  | 
398  | /*++++++++++++++++++++++++++++++++++++++
399  |   A function to get some memory for a string, allocate a new heap structure if needed.
400  | 
401  |   char* get_space Returns a pointer to enough space.
402  | 
403  |   unsigned int l The amount of space that is needed.
404  |   ++++++++++++++++++++++++++++++++++++++*/
405  | 
406  | static char* get_space(unsigned int l)
407  | {
408  |  static Heap current=NULL;
409  |  char* r=NULL;
410  | 
411  |  if(l <= SMALL_STRING)
412  |    {
413  |     if(heap_left < l)
414  |       {
415  |        current=add_to_heap(HEAP_INC);
416  |        heap_left=HEAP_INC;
417  |       }
418  | 
419  |     heap_left-=l;
420  | 
421  |     r=&current->mem[heap_left]; /* Work downwards */
422  |    }
423  |  else
424  |    {
425  |     Heap h=add_to_heap(l);
426  |     r=h->mem;
427  |    }
428  | 
429  |  return(r);
430  | }
431  | 
432  | 
433  | /*++++++++++++++++++++++++++++++++++++++
434  |   Add some bytes to the privately maintained memory heap.
435  | 
436  |   Heap add_to_heap Returns a pointer to the required memory.
437  | 
438  |   unsigned int l The size of the memory that is required.
439  |   ++++++++++++++++++++++++++++++++++++++*/
440  | 
441  | static Heap add_to_heap(unsigned int l)
442  | {
443  |  Heap* h=&first;
444  | 
445  |  while(*h)
446  |     h=&(*h)->next;
447  | 
448  |  *h=(Heap)Malloc(sizeof(struct _Heap));
449  |  (*h)->next=NULL;
450  |  (*h)->mem=(char*)Malloc(l);
451  | 
452  |  return(*h);
453  | }