• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**********************************************************************
2  * File:        memry.c  (Formerly memory.c)
3  * Description: Memory allocation with builtin safety checks.
4  * Author:					Ray Smith
5  * Created:					Wed Jan 22 09:43:33 GMT 1992
6  *
7  * (C) Copyright 1992, Hewlett-Packard Ltd.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  *
18  **********************************************************************/
19 
20 #include          "mfcpch.h"
21 #include          <stdlib.h>
22 #ifdef __UNIX__
23 #include          <assert.h>
24 #endif
25 #include          "stderr.h"
26 #include          "tprintf.h"
27 #include          "memblk.h"
28 #include          "memry.h"
29 
30 //#define COUNTING_CLASS_STRUCTURES
31 
32 /**********************************************************************
33  * new
34  *
35  * Replace global new to get at memory leaks etc.
36  **********************************************************************/
37 /*
38 void*						operator new(				//allocate memory
39 size_t						size						//amount to allocate
40 )
41 {
42   if (size==0)
43   {
44     err.log(RESULT_LOGICAL_ERROR,E_LOC,ERR_PRIMITIVES,
45       ERR_SCROLLING,ERR_CONTINUE,ERR_ERROR,
46       "Zero requested of new");
47     size=1;
48   }
49   return alloc_big_mem(size);
50 }
51 
52 void						operator delete(			//free memory
53 void*						addr						//mem to free
54 )
55 {
56   free_big_mem(addr);
57 }*/
58 
59 /**********************************************************************
60  * check_mem
61  *
62  * Check consistency of all memory controlled by alloc_mem.
63  **********************************************************************/
64 
check_mem(const char * string,inT8 level)65 DLLSYM void check_mem(                     //check consistency
66                       const char *string,  //context message
67                       inT8 level           //level of check
68                      ) {
69   big_mem.check (string, level);
70   main_mem.check (string, level);
71   check_structs(level);
72 }
73 
74 
75 /**********************************************************************
76  * alloc_string
77  *
78  * Allocate space for a string.  The space can only be used for chars as
79  * it is not aligned.  Allocation is guaranteed to be fast and not cause
80  * fragmentation for small strings (upto 10*worst alignment).  Calls for
81  * larger strings will be satisfied with alloc_mem.
82  * Use free_string to free the space from alloc_string.
83  **********************************************************************/
84 
alloc_string(inT32 count)85 DLLSYM char *alloc_string(             //allocate string
86                           inT32 count  //no of chars required
87                          ) {
88 #ifdef RAYS_MALLOC
89   char *string;                  //allocated string
90 
91   if (count < 1 || count > MAX_CHUNK) {
92     tprintf ("Invalid size %d requested of alloc_string", count);
93     return NULL;
94   }
95 
96   count++;                       //add size byte
97   if (count <= MAX_STRUCTS * sizeof (MEMUNION)) {
98     string = (char *) alloc_struct (count, "alloc_string");
99     //get a fast structure
100     if (string == NULL) {
101       tprintf ("No memory for alloc_string");
102       return NULL;
103     }
104     string[0] = (inT8) count;    //save its length
105   }
106   else {
107                                  //get a big block
108     string = (char *) alloc_mem (count);
109     if (string == NULL) {
110       tprintf ("No memory for alloc_string");
111       return NULL;
112     }
113     string[0] = 0;               //mark its id
114   }
115   return &string[1];             //string for user
116 #else
117   // Round up the amount allocated to a multiple of 4
118   return static_cast<char*>(malloc((count + 3) & ~3));
119 #endif
120 }
121 
122 
123 /**********************************************************************
124  * free_string
125  *
126  * Free a string allocated by alloc_string.
127  **********************************************************************/
128 
free_string(char * string)129 DLLSYM void free_string(              //free a string
130                         char *string  //string to free
131                        ) {
132 #ifdef RAYS_MALLOC
133   if (((ptrdiff_t) string & 3) == 1) { //one over word
134     string--;                    //get id marker
135     if (*string == 0) {
136       free_mem(string);  //generally free it
137       return;
138     }
139     else if (*string <= MAX_STRUCTS * sizeof (MEMUNION)) {
140                                  //free structure
141       free_struct (string, *string, "alloc_string");
142       return;
143     }
144   }
145   tprintf ("Non-string given to free_string");
146 #else
147   free(string);
148 #endif
149 }
150 
151 
152 /**********************************************************************
153  * alloc_struct
154  *
155  * Allocate space for a structure.  This function is designed to be
156  * fast and fragmentation free for arbitrary combinations of small
157  * objects. (Upto 40 bytes in length.)
158  * It can be used for any size of object up to 512K, but you must use
159  * free_struct to release the memory it gives.  alloc_mem is better
160  * for arbitrary data blocks of large size (>40 bytes.)
161  * alloc_struct always aborts if the allocation fails.
162  **********************************************************************/
163 
164 DLLSYM void *
alloc_struct(inT32 count,const char * name)165 alloc_struct (                   //allocate memory
166 inT32 count,                     //no of chars required
167 #if defined COUNTING_CLASS_STRUCTURES
168 const char *name                 //name of type
169 #else
170 const char *                     //name of type
171 #endif
172 ) {
173 #ifdef RAYS_MALLOC
174   MEMUNION *element;             //current element
175   MEMUNION *returnelement;       //return value
176   inT32 struct_count;            //no of required structs
177   inT32 blocksize;               //no of structs in block
178   inT32 index;                   //index to structure
179 
180   if (count < 1 || count > MAX_CHUNK) {
181     tprintf ("Invalid size %d requested of alloc_struct", count);
182     return NULL;
183   }
184 
185   //      tprintf("Allocating structure of size %d\n",count);
186                                  //no of MEMUNIONS-1
187   struct_count = (count - 1) / sizeof (MEMUNION);
188   if (struct_count < MAX_STRUCTS) {
189                                  //can do fixed sizes
190     #ifdef COUNTING_CLASS_STRUCTURES
191     if (name != NULL) {
192       index = identify_struct_owner (struct_count, name);
193       if (index < MAX_CLASSES)
194         owner_counts[struct_count][index]++;
195     }
196     #endif
197                                  //head of freelist
198     returnelement = free_structs[struct_count];
199     if (returnelement == NULL) {
200                                  //need a new block
201                                  //get one
202       element = (MEMUNION *) new_struct_block ();
203       if (element == NULL) {
204         tprintf ("No memory to satisfy request for %d", (int) count);
205         return NULL;
206       }
207                                  //add to block list
208       element->ptr = struct_blocks[struct_count];
209       struct_blocks[struct_count] = element;
210       blocks_in_use[struct_count]++;
211       element++;                 //free cell
212       returnelement = element;   //going to return 1st
213       blocksize = STRUCT_BLOCK_SIZE / (struct_count + 1) - 1;
214 
215       for (index = 1; index < blocksize; index++) {
216                                  //make links
217         element->ptr = element + struct_count + 1;
218         element += struct_count + 1;
219       }
220       element->ptr = NULL;       //end of freelist
221     }
222                                  //new free one
223     free_structs[struct_count] = returnelement->ptr;
224                                  //count number issued
225     structs_in_use[struct_count]++;
226   }
227   else {
228                                  //just get some
229     returnelement = (MEMUNION *) alloc_mem (count);
230     if (returnelement == NULL) {
231       tprintf ("No memory to satisfy request for %d", (int) count);
232       return NULL;
233     }
234   }
235   return returnelement;          //free cell
236 #else
237   return malloc(count);
238 #endif
239 }
240 
241 
242 /**********************************************************************
243  * free_struct
244  *
245  * Free memory allocated by alloc_struct.  The size must be supplied.
246  **********************************************************************/
247 
248 DLLSYM void
free_struct(void * deadstruct,inT32 count,const char * name)249 free_struct (                    //free a structure
250 void *deadstruct,                //structure to free
251 inT32 count,                     //no of bytes
252 #if defined COUNTING_CLASS_STRUCTURES
253 const char *name                 //name of type
254 #else
255 const char *                     //name of type
256 #endif
257 ) {
258 #ifdef RAYS_MALLOC
259   MEMUNION *end_element;         //current element
260   MEMUNION *element;             //current element
261   MEMUNION *prev_element;        //previous element
262   MEMUNION *prev_block;          //previous element
263   MEMUNION *nextblock;           //next block in list
264   MEMUNION *block;               //next block in list
265   inT32 struct_count;            //no of required structs
266   inT32 index;                   //to structure counts
267 
268   if (count < 1 || count > MAX_CHUNK) {
269     tprintf ("Invalid size %d requested of free_struct", count);
270     return;
271   }
272 
273   //      tprintf("Freeing structure of size %d\n",count);
274                                  //no of MEMUNIONS-1
275   struct_count = (count - 1) / sizeof (MEMUNION);
276 
277   if (deadstruct == NULL) {
278                                  //not really legal
279     check_struct(MEMCHECKS, count);
280   }
281   else {
282     if (struct_count < MAX_STRUCTS) {
283                                  //can do fixed sizes
284       #ifdef COUNTING_CLASS_STRUCTURES
285       if (name != NULL) {
286         index = identify_struct_owner (struct_count, name);
287         if (index < MAX_CLASSES) {
288           owner_counts[struct_count][index]--;
289           ASSERT_HOST (owner_counts[struct_count][index] >= 0);
290         }
291       }
292       #endif
293       element = (MEMUNION *) deadstruct;
294                                  //add to freelist
295       element->ptr = free_structs[struct_count];
296       free_structs[struct_count] = element;
297                                  //one less in use
298       structs_in_use[struct_count]--;
299       if (structs_in_use[struct_count] == 0) {
300         index = 0;
301         for (element = struct_blocks[struct_count];
302         element != NULL; element = nextblock) {
303                                  //traverse and destroy
304           nextblock = element->ptr;
305                                  //free all the blocks
306           old_struct_block(element);
307           index++;
308         }
309                                  //none left any more
310         struct_blocks[struct_count] = NULL;
311                                  //no free structs
312         free_structs[struct_count] = NULL;
313         blocks_in_use[struct_count] = 0;
314       }
315       else if (structs_in_use[struct_count] < 0) {
316         tprintf ("Negative number of structs of size %d in use",
317           (int) count);
318       }
319       else if (structs_in_use[struct_count] < blocks_in_use[struct_count]) {
320         prev_block = NULL;
321         for (block = struct_blocks[struct_count];
322         block != NULL; block = nextblock) {
323           nextblock = block;
324           index = STRUCT_BLOCK_SIZE / (struct_count + 1) - 1;
325           end_element = block + STRUCT_BLOCK_SIZE;
326           for (element = free_structs[struct_count];
327           element != NULL; element = element->ptr) {
328             if (element > nextblock && element < end_element) {
329               index--;
330               if (index == 0)
331                 break;
332             }
333           }
334           if (index == 0) {
335             index = STRUCT_BLOCK_SIZE / (struct_count + 1) - 1;
336             for (element =
337               free_structs[struct_count], prev_element = NULL;
338             element != NULL; element = element->ptr) {
339               if (element > nextblock && element < end_element) {
340                 index--;
341                 if (prev_element != NULL)
342                   prev_element->ptr = element->ptr;
343                 else
344                   free_structs[struct_count] = element->ptr;
345                 if (index == 0)
346                   break;
347               }
348               else
349                 prev_element = element;
350             }
351             if (prev_block != NULL)
352               prev_block->ptr = block->ptr;
353             else
354               struct_blocks[struct_count] = block->ptr;
355             nextblock = block->ptr;
356             blocks_in_use[struct_count]--;
357                                  //free all the blocks
358             old_struct_block(block);
359           }
360           else {
361             prev_block = block;
362                                  //traverse and destroy
363             nextblock = block->ptr;
364           }
365         }
366       }
367     }
368     else
369       free_mem(deadstruct);  //free directly
370   }
371 #else
372   free(deadstruct);
373 #endif
374 }
375 
376 
377 /**********************************************************************
378  * alloc_mem_p
379  *
380  * Allocate permanent space which will never be returned.
381  * This space is allocated from the top end of a memory block to
382  * avoid the fragmentation which would result from alternate use
383  * of alloc_mem for permanent and temporary blocks.
384  **********************************************************************/
385 
386 //#ifdef __UNIX__
387 //#pragma OPT_LEVEL 0
388 //#endif
alloc_mem_p(inT32 count)389 DLLSYM void *alloc_mem_p(             //allocate permanent space
390                          inT32 count  //block size to allocate
391                         ) {
392   #ifdef RAYS_MALLOC
393   #ifdef TESTING_BIGSTUFF
394   if (main_mem.biggestblock == 0)
395     main_mem.init (alloc_big_mem, free_big_mem,
396       FIRSTSIZE, LASTSIZE, MAX_CHUNK);
397   #else
398   if (main_mem.biggestblock == 0)
399     main_mem.init ((void *(*)(inT32)) malloc, free,
400       FIRSTSIZE, LASTSIZE, MAX_CHUNK);
401   #endif
402   if (mem_mallocdepth > 0)
403     return main_mem.alloc_p (count, trace_caller (mem_mallocdepth));
404   else
405     return main_mem.alloc_p (count, NULL);
406   #else
407   return malloc ((size_t) count);
408   #endif
409 }
410 
411 
412 /**********************************************************************
413  * alloc_mem
414  *
415  * Return a pointer to a buffer of count bytes aligned for any type.
416  **********************************************************************/
417 
alloc_mem(inT32 count)418 DLLSYM void *alloc_mem(             //get some memory
419                        inT32 count  //no of bytes to get
420                       ) {
421   #ifdef RAYS_MALLOC
422   #ifdef TESTING_BIGSTUFF
423   if (main_mem.biggestblock == 0)
424     main_mem.init (alloc_big_mem, free_big_mem,
425       FIRSTSIZE, LASTSIZE, MAX_CHUNK);
426   #else
427   if (main_mem.biggestblock == 0)
428     main_mem.init ((void *(*)(inT32)) malloc, free,
429       FIRSTSIZE, LASTSIZE, MAX_CHUNK);
430   #endif
431   if (mem_mallocdepth > 0)
432     return main_mem.alloc (count, trace_caller (mem_mallocdepth));
433   else
434     return main_mem.alloc (count, NULL);
435   #else
436   return malloc ((size_t) count);
437   #endif
438 }
439 
440 
441 /**********************************************************************
442  * alloc_big_mem
443  *
444  * Return a pointer to a buffer of count bytes aligned for any type.
445  **********************************************************************/
446 
alloc_big_mem(inT32 count)447 DLLSYM void *alloc_big_mem(             //get some memory
448                            inT32 count  //no of bytes to get
449                           ) {
450   #ifdef TESTING_BIGSTUFF
451   if (big_mem.biggestblock == 0)
452     big_mem.init ((void *(*)(inT32)) malloc, free,
453       BIGSIZE, BIGSIZE, MAX_BIGCHUNK);
454   if (mem_mallocdepth > 0)
455     return big_mem.alloc (count, trace_caller (mem_mallocdepth));
456   else
457     return big_mem.alloc (count, NULL);
458   #else
459   return malloc ((size_t) count);
460   #endif
461 }
462 
463 
464 /**********************************************************************
465  * alloc_big_zeros
466  *
467  * Return a pointer to a buffer of count bytes aligned for any type.
468  **********************************************************************/
469 
alloc_big_zeros(inT32 count)470 DLLSYM void *alloc_big_zeros(             //get some memory
471                              inT32 count  //no of bytes to get
472                             ) {
473   #ifdef TESTING_BIGSTUFF
474   if (big_mem.biggestblock == 0)
475     big_mem.init ((void *(*)(inT32)) malloc, free,
476       BIGSIZE, BIGSIZE, MAX_BIGCHUNK);
477   void *buf;                     //return value
478 
479   if (mem_mallocdepth > 0)
480     buf = big_mem.alloc (count, trace_caller (mem_mallocdepth));
481   else
482     buf = big_mem.alloc (count, NULL);
483   memset (buf, 0, count);
484   return buf;
485   #else
486   return calloc ((size_t) count, 1);
487   #endif
488 }
489 
490 
491 /**********************************************************************
492  * free_mem
493  *
494  * Free a block allocated by alloc_mem (or alloc_mem_p).
495  * It checks that the pointer is legal and maintains counts of the
496  * amount of free memory above and below the current free pointer.
497  **********************************************************************/
498 
free_mem(void * oldchunk)499 DLLSYM void free_mem(                //free mem from alloc_mem
500                      void *oldchunk  //chunk to free
501                     ) {
502   #ifdef RAYS_MALLOC
503   if (mem_freedepth > 0 && main_mem.callers != NULL)
504     main_mem.dealloc (oldchunk, trace_caller (mem_freedepth));
505   else
506     main_mem.dealloc (oldchunk, NULL);
507   #else
508   free(oldchunk);
509   #endif
510 }
511 
512 
513 /**********************************************************************
514  * free_big_mem
515  *
516  * Free a block allocated by alloc_big_mem.
517  * It checks that the pointer is legal and maintains counts of the
518  * amount of free memory above and below the current free pointer.
519  **********************************************************************/
520 
free_big_mem(void * oldchunk)521 DLLSYM void free_big_mem(                //free mem from alloc_mem
522                          void *oldchunk  //chunk to free
523                         ) {
524   #ifdef TESTING_BIGSTUFF
525   if (mem_freedepth > 0 && main_mem.callers != NULL)
526     big_mem.dealloc (oldchunk, trace_caller (mem_freedepth));
527   else
528     big_mem.dealloc (oldchunk, NULL);
529   #else
530   free(oldchunk);
531   #endif
532 }
533