1 | /*************************************** 2 | $Header: /home/amb/CVS/cxref/src/memory.c,v 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=¤t->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 | }