1 |
/* |
2 |
* Ascend Memory Allocation Routines |
3 |
* by Tom Epperly |
4 |
* Created: 2/6/90 |
5 |
* Version: $Revision: 1.1 $ |
6 |
* Version control file: $RCSfile: ascMalloc.c,v $ |
7 |
* Date last modified: $Date: 1997/07/18 11:44:49 $ |
8 |
* Last modified by: $Author: mthomas $ |
9 |
* |
10 |
* This file is part of the Ascend Language Interpreter. |
11 |
* |
12 |
* Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly |
13 |
* |
14 |
* The Ascend Language Interpreter is free software; you can redistribute |
15 |
* it and/or modify it under the terms of the GNU General Public License |
16 |
* as published by the Free Software Foundation; either version 2 of the |
17 |
* License, or (at your option) any later version. |
18 |
* |
19 |
* The Ascend Language Interpreter is distributed in hope that it will be |
20 |
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
22 |
* General Public License for more details. |
23 |
* |
24 |
* You should have received a copy of the GNU General Public License |
25 |
* along with the program; if not, write to the Free Software Foundation, |
26 |
* Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named |
27 |
* COPYING. |
28 |
*/ |
29 |
|
30 |
#include <stdio.h> |
31 |
#include <limits.h> |
32 |
#include <time.h> |
33 |
#include <malloc.h> |
34 |
#include <stdlib.h> |
35 |
#include <sys/types.h> |
36 |
#include <sys/stat.h> |
37 |
#include <fcntl.h> |
38 |
#include "utilities/ascConfig.h" |
39 |
#ifndef __WIN32__ |
40 |
# include <unistd.h> |
41 |
#else |
42 |
# include <io.h> /* _open() declared here in MSVC */ |
43 |
#endif |
44 |
#include "compiler/compiler.h" |
45 |
#include "utilities/ascPanic.h" |
46 |
#include "utilities/ascMalloc.h" |
47 |
|
48 |
#define MAXPOINTERS 1000000 |
49 |
|
50 |
/* temporary file support */ |
51 |
#ifdef __WIN32__ |
52 |
# define LOGFILE "memlg" |
53 |
#else |
54 |
# define TEMPFILE_TEMPLATE "/tmp/ascmemlog_XXXXXX" |
55 |
#endif |
56 |
|
57 |
#ifndef lint |
58 |
static CONST char AscendMemoryAllocRCSid[]="$Rev$"; |
59 |
#endif |
60 |
|
61 |
/* |
62 |
* The "non-debug" version of ascstrdupf - |
63 |
* all memory calls should be to the system versions. |
64 |
*/ |
65 |
char *ascstrdupf(char *s) |
66 |
{ |
67 |
char *result; |
68 |
|
69 |
if (NULL == s) { |
70 |
return NULL; |
71 |
} |
72 |
result = (char *)malloc(strlen(s) + 1); |
73 |
if (NULL != result) { |
74 |
strcpy(result, s); |
75 |
} |
76 |
return result; |
77 |
} |
78 |
|
79 |
|
80 |
/* |
81 |
* Here's the debug version of ascstrdup - |
82 |
* all memory calls should be to the local debug versions. |
83 |
*/ |
84 |
char *ascstrdupf_dbg(char *s) |
85 |
{ |
86 |
char *result; |
87 |
|
88 |
if (NULL == s) { |
89 |
return NULL; |
90 |
} |
91 |
result = (char *)ascmallocf(strlen(s) + 1, __FILE__, __LINE__); |
92 |
if (NULL != result) { |
93 |
strcpy(result, s); |
94 |
} |
95 |
return result; |
96 |
} |
97 |
|
98 |
char *asc_memcpy(char *to, char *from, size_t size) |
99 |
{ |
100 |
/* We really should be moving stuff a long at a time, but that mean |
101 |
* handling the leading and trailing unaligned bytes separately. |
102 |
* We also really should just be passing on to the vendor memcpy on |
103 |
* those systems which do overlapping ranges right. |
104 |
*/ |
105 |
char *fill; |
106 |
asc_assert((size == 0) || ((NULL != to) && (NULL != from))); |
107 |
if (from < to) { |
108 |
fill = (to + size) - 1; |
109 |
from += (size - 1); |
110 |
while (size-- > 0) { |
111 |
*fill-- = *from--; |
112 |
} |
113 |
} else { |
114 |
if (from > to) { |
115 |
fill = to; |
116 |
while (size-- > 0) { |
117 |
*fill++ = *from++; |
118 |
} |
119 |
} /* else from == to, do nothing */ |
120 |
} |
121 |
return to; |
122 |
} |
123 |
|
124 |
/* |
125 |
* The "non-debug" version of ascreallocPURE - |
126 |
* all memory calls should be to the system versions. |
127 |
*/ |
128 |
char *ascreallocPUREF(char *ptr, size_t oldbytes, size_t newbytes) |
129 |
{ |
130 |
/* shrink */ |
131 |
if (newbytes > 0 && newbytes <= oldbytes) return ptr; |
132 |
/* release */ |
133 |
if (!newbytes) { |
134 |
free(ptr); |
135 |
return NULL; |
136 |
} |
137 |
/* create */ |
138 |
if (!oldbytes) { |
139 |
if (ptr!=NULL) free(ptr); /* some OS allocate 0 bytes, god help us */ |
140 |
return (char *)malloc(newbytes); |
141 |
} else { |
142 |
/* expand */ |
143 |
char *ret; |
144 |
ret = malloc(newbytes); |
145 |
if (ret==NULL) return NULL; |
146 |
if (oldbytes%sizeof(long) == 0 && ((unsigned long)ptr)%sizeof(long) == 0) { |
147 |
register unsigned long c,len, *src, *trg; |
148 |
src = (unsigned long *)ptr; |
149 |
trg = (unsigned long *)ret; |
150 |
len = oldbytes/sizeof(long); |
151 |
for (c=0;c < len;c++) trg[c]=src[c]; /* copy data as longs */ |
152 |
} else { |
153 |
memcpy(ret,ptr,oldbytes); |
154 |
} |
155 |
free(ptr); |
156 |
return ret; |
157 |
} |
158 |
} |
159 |
|
160 |
/* |
161 |
* Here's the debug version of ascreallocPURE - |
162 |
* all memory calls should be to the local debug versions. |
163 |
*/ |
164 |
char *ascreallocPUREF_dbg(char *ptr, size_t oldbytes, size_t newbytes) |
165 |
{ |
166 |
/* shrink */ |
167 |
if (newbytes > 0 && newbytes <= oldbytes) return ptr; |
168 |
/* release */ |
169 |
if (!newbytes) { |
170 |
ascfreef(ptr, __FILE__, __LINE__); |
171 |
return NULL; |
172 |
} |
173 |
/* create */ |
174 |
if (!oldbytes) { |
175 |
if (ptr!=NULL) ascfreef(ptr, __FILE__, __LINE__); /* some OS allocate 0 bytes, god help us */ |
176 |
return (char *)ascmallocf(newbytes, __FILE__, __LINE__); |
177 |
} else { |
178 |
/* expand */ |
179 |
char *ret; |
180 |
ret = ascmallocf(newbytes, __FILE__, __LINE__); |
181 |
if (ret==NULL) return NULL; |
182 |
if (oldbytes%sizeof(long) == 0 && ((unsigned long)ptr)%sizeof(long) == 0) { |
183 |
register unsigned long c,len, *src, *trg; |
184 |
src = (unsigned long *)ptr; |
185 |
trg = (unsigned long *)ret; |
186 |
len = oldbytes/sizeof(long); |
187 |
for (c=0;c < len;c++) trg[c]=src[c]; /* copy data as longs */ |
188 |
} else { |
189 |
memcpy(ret,ptr,oldbytes); |
190 |
} |
191 |
ascfreef(ptr, __FILE__, __LINE__); |
192 |
return ret; |
193 |
} |
194 |
} |
195 |
|
196 |
struct memory_rec{ |
197 |
CONST VOIDPTR ptr; |
198 |
size_t size; |
199 |
}; |
200 |
|
201 |
#ifdef __WIN32__ |
202 |
static char *f_memlog_filename = NULL; |
203 |
#endif |
204 |
static FILE *f_memory_log_file = NULL; |
205 |
static int f_memory_length = 0; |
206 |
static unsigned long f_memory_allocated = 0L; |
207 |
static unsigned long f_peak_memory_usage = 0L; |
208 |
static struct memory_rec f_mem_rec[MAXPOINTERS]; |
209 |
|
210 |
unsigned long ascmeminusef(void) |
211 |
{ |
212 |
return f_memory_allocated; |
213 |
} |
214 |
|
215 |
#ifdef THIS_IS_AN_UNUSED_FUNCTION |
216 |
/*@unused@*/ |
217 |
static int SortedList(void) |
218 |
{ |
219 |
int c; |
220 |
for(c=1;c<f_memory_length;c++) |
221 |
if (f_mem_rec[c-1].ptr>f_mem_rec[c].ptr) return 0; |
222 |
return 1; |
223 |
} |
224 |
#endif /* THIS_IS_AN_UNUSED_FUNCTION */ |
225 |
|
226 |
static CONST VOIDPTR MinMemory(void) |
227 |
{ |
228 |
int c; |
229 |
CONST VOIDPTR minm=(VOIDPTR)ULONG_MAX; |
230 |
for(c=0;c<f_memory_length;c++) |
231 |
if (f_mem_rec[c].ptr < minm) minm = f_mem_rec[c].ptr; |
232 |
return minm; |
233 |
} |
234 |
|
235 |
static CONST VOIDPTR MaxMemory(void) |
236 |
{ |
237 |
int c; |
238 |
CONST VOIDPTR maxm=0; |
239 |
for(c=0;c<f_memory_length;c++) |
240 |
if (((CONST char *)f_mem_rec[c].ptr + f_mem_rec[c].size - 1) |
241 |
> (CONST char *)maxm) |
242 |
maxm = (CONST VOIDPTR)((CONST char *)f_mem_rec[c].ptr + f_mem_rec[c].size - 1); |
243 |
return maxm; |
244 |
} |
245 |
|
246 |
#define NONZERO(x) ((0 != (x)) ? (x) : 1) |
247 |
|
248 |
static CONST VOIDPTR MemoryMean(void) |
249 |
{ |
250 |
int c; |
251 |
size_t size; |
252 |
double sum=0.0, bytes=0.0; |
253 |
for(c=0 ; c<f_memory_length ; c++){ |
254 |
size = f_mem_rec[c].size; |
255 |
if (0 != size){ |
256 |
bytes += (double)size; |
257 |
sum += (double)((size * (size-1))/2) |
258 |
+ ((double)size) * ((double)(unsigned long)f_mem_rec[c].ptr); |
259 |
} |
260 |
} |
261 |
return (VOIDPTR)(unsigned long)(sum/NONZERO(bytes)); |
262 |
} |
263 |
|
264 |
/* |
265 |
* Creates a temporary file for logging memory events. |
266 |
* The file is opened and header information is written to it. |
267 |
* Thereafter, the FILE* is available to other routines in |
268 |
* f_memory_log_file, which should append to the file as needed. |
269 |
* This function may be called more than once - the file will only be |
270 |
* created and header info written the first time it is called, or |
271 |
* after ascshutdown() has been called. |
272 |
*/ |
273 |
static void OpenLogFile(void) |
274 |
{ |
275 |
time_t t; |
276 |
int handle; |
277 |
|
278 |
if (NULL == f_memory_log_file) { |
279 |
|
280 |
#ifdef __WIN32__ |
281 |
/* Windows doesn't have mkstemp(), so need to use tempnam() */ |
282 |
f_memlog_filename = tempnam(NULL, LOGFILE); |
283 |
if (NULL == f_memlog_filename) { |
284 |
Asc_Panic(2, NULL, "Unable to create a unique memory log filename.\n"); |
285 |
} |
286 |
handle = _open(f_memlog_filename, |
287 |
O_WRONLY | O_CREAT | O_EXCL | O_TEXT, |
288 |
_S_IREAD | _S_IWRITE); |
289 |
if ((-1 == handle) || |
290 |
(NULL == (f_memory_log_file = fdopen(handle,"w")))) { |
291 |
Asc_Panic(2, NULL, "Unable to open memory log file.\n"); |
292 |
} |
293 |
#else |
294 |
char temp_filename[] = TEMPFILE_TEMPLATE; |
295 |
handle = mkstemp(temp_filename); |
296 |
if ((-1 == handle) || |
297 |
(NULL == (f_memory_log_file = fdopen(handle,"r+")))) { |
298 |
Asc_Panic(2, NULL, "Unable to open memory log file.\n"); |
299 |
} |
300 |
#endif /* __WIN32__ */ |
301 |
|
302 |
t = time((time_t *)NULL); |
303 |
FPRINTF(f_memory_log_file,"Ascend memory log file opened %s", |
304 |
asctime(localtime(&t))); |
305 |
FPRINTF(f_memory_log_file,"%16s %13s %16s %13s %6s %s", |
306 |
"Alloc Range", |
307 |
"Size", |
308 |
"Dealloc Range", |
309 |
"Size", |
310 |
"Line#", |
311 |
"Source File\n"); |
312 |
fflush(f_memory_log_file); |
313 |
} |
314 |
} |
315 |
|
316 |
static void WriteMemoryStatus(FILE *f, CONST char *msg) |
317 |
{ |
318 |
CONST VOIDPTR minm; |
319 |
CONST VOIDPTR maxm; |
320 |
minm = MinMemory(); |
321 |
maxm = MaxMemory(); |
322 |
FPRINTF(f,"%s\n" |
323 |
"Current memory usage(byte allocated): %lu\n" |
324 |
"Current number of blocks: %d\n" |
325 |
"Peak memory usage(bytes allocated): %lu\n" |
326 |
"Lowest address: %lx\n" |
327 |
"Highest address: %lx\n" |
328 |
"Memory density: %g\n" |
329 |
"Memory mean: %lx\n", |
330 |
msg, |
331 |
f_memory_allocated, |
332 |
f_memory_length, |
333 |
f_peak_memory_usage, |
334 |
(unsigned long)minm, |
335 |
(unsigned long)maxm, |
336 |
((double)f_memory_allocated/(double) |
337 |
NONZERO((CONST char *)maxm - (CONST char *)minm)), |
338 |
(unsigned long)MemoryMean()); |
339 |
} |
340 |
|
341 |
static void WriteMemoryRecords(FILE *f, CONST char *msg) |
342 |
{ |
343 |
int c; |
344 |
FPRINTF(f,"%s\nAllocation record count: %d\n", msg, f_memory_length); |
345 |
for (c=0 ; c<f_memory_length ; ++c) { |
346 |
FPRINTF(f,"%5d %9x->%9x %9u\n", |
347 |
c, |
348 |
f_mem_rec[c].ptr, |
349 |
(CONST VOIDPTR)((CONST char *)f_mem_rec[c].ptr + f_mem_rec[c].size), |
350 |
f_mem_rec[c].size); |
351 |
} |
352 |
} |
353 |
|
354 |
void ascstatusf(CONST char *msg) |
355 |
{ |
356 |
OpenLogFile(); |
357 |
if (NULL != f_memory_log_file) { |
358 |
WriteMemoryStatus(f_memory_log_file, msg); |
359 |
fflush(f_memory_log_file); |
360 |
} |
361 |
WriteMemoryStatus(ASCINF, msg); |
362 |
} |
363 |
|
364 |
void ascstatus_detailf(CONST char *msg) |
365 |
{ |
366 |
OpenLogFile(); |
367 |
if (NULL != f_memory_log_file) { |
368 |
WriteMemoryStatus(f_memory_log_file, msg); |
369 |
WriteMemoryRecords(f_memory_log_file, "\nDetail Report of Currently Allocated Blocks"); |
370 |
fflush(f_memory_log_file); |
371 |
} |
372 |
WriteMemoryStatus(ASCINF, msg); |
373 |
WriteMemoryRecords(ASCINF, "\nDetail Report of Currently Allocated Blocks"); |
374 |
} |
375 |
|
376 |
void ascshutdownf(CONST char *msg) |
377 |
{ |
378 |
OpenLogFile(); |
379 |
if (NULL != f_memory_log_file) { |
380 |
WriteMemoryStatus(f_memory_log_file,msg); |
381 |
if (f_memory_length) { |
382 |
WriteMemoryRecords(f_memory_log_file, "\n!!! SHUTDOWN ALERT -- POINTERS STILL ALLOCATED !!!"); |
383 |
FPRINTF(f_memory_log_file, "!!! END OF SHUTDOWN MESSAGE !!!\n"); |
384 |
} else { |
385 |
FPRINTF(f_memory_log_file, "NO POINTERS STILL ALLOCATED :-)\n"); |
386 |
} |
387 |
fflush(f_memory_log_file); |
388 |
#ifdef __WIN32__ |
389 |
FPRINTF(ASCINF, "Memory log written to: %s\n", f_memlog_filename); |
390 |
free(f_memlog_filename); /* free(), NOT ascfree() */ |
391 |
f_memlog_filename = NULL; |
392 |
#else |
393 |
FPRINTF(ASCINF, "Memory log file written & closed.\n"); |
394 |
#endif |
395 |
fclose(f_memory_log_file); |
396 |
f_memory_log_file = NULL; |
397 |
} |
398 |
WriteMemoryStatus(ASCINF, msg); |
399 |
if (f_memory_length) { |
400 |
WriteMemoryRecords(ASCINF, "\n!!! SHUTDOWN ALERT -- POINTERS STILL ALLOCATED !!!"); |
401 |
FPRINTF(ASCINF, "!!! END OF SHUTDOWN MESSAGE !!!\n"); |
402 |
} else { |
403 |
FPRINTF(ASCINF, "NO POINTERS STILL ALLOCATED :-)\n"); |
404 |
} |
405 |
} |
406 |
|
407 |
static void WriteAllocation(CONST VOIDPTR adr, size_t size, |
408 |
CONST char *file, int line) |
409 |
{ |
410 |
if (NULL != f_memory_log_file) { |
411 |
FPRINTF(f_memory_log_file,"%9lx->%9x %9u %31s%6d %s\n", |
412 |
(unsigned long)adr, |
413 |
(unsigned long)adr + size - 1, |
414 |
size, |
415 |
"", |
416 |
line, |
417 |
file); |
418 |
fflush(f_memory_log_file); |
419 |
} |
420 |
else{ |
421 |
FPRINTF(ASCERR,"Unable to append to memory log file.\n"); |
422 |
FPRINTF(ASCERR,"%9lx->%9x %9u %31s%6d %s\n", |
423 |
(unsigned long)adr, |
424 |
(unsigned long)adr + size - 1, |
425 |
size, |
426 |
"", |
427 |
line, |
428 |
file); |
429 |
} |
430 |
} |
431 |
|
432 |
static void WriteReAllocation(CONST VOIDPTR adr1, size_t size1, |
433 |
CONST VOIDPTR adr2, size_t size2, |
434 |
CONST char *file, int line) |
435 |
{ |
436 |
if (NULL != f_memory_log_file) { |
437 |
FPRINTF(f_memory_log_file,"%9lx->%9x %9u %9lx->%9x %9u %6d %s\n", |
438 |
(unsigned long)adr2, |
439 |
(unsigned long)adr2 + size2 - 1, |
440 |
size2, |
441 |
(unsigned long)adr1, |
442 |
(unsigned long)adr1 + size1 - 1, |
443 |
size1, line, file); |
444 |
fflush(f_memory_log_file); |
445 |
} |
446 |
else{ |
447 |
FPRINTF(ASCERR,"Unable to append to memory log file.\n"); |
448 |
FPRINTF(ASCERR,"%9lx->%9x %9u %9lx->%9x %9u %6d %s\n", |
449 |
(unsigned long)adr2, |
450 |
(unsigned long)adr2 + size2 - 1, |
451 |
size2, |
452 |
(unsigned long)adr1, |
453 |
(unsigned long)adr1 + size1 - 1, |
454 |
size1, line, file); |
455 |
} |
456 |
} |
457 |
|
458 |
static void WriteDeallocation(CONST VOIDPTR adr, size_t size, |
459 |
CONST char *file, int line) |
460 |
{ |
461 |
if (NULL != f_memory_log_file) { |
462 |
FPRINTF(f_memory_log_file,"%31s%9x->%9x %9u %6d %s\n","", |
463 |
(unsigned long)adr, |
464 |
(unsigned long)adr + size - 1, |
465 |
size, line, file); |
466 |
fflush(f_memory_log_file); |
467 |
} |
468 |
else{ |
469 |
FPRINTF(ASCERR,"Unable to append to memory log file.\n"); |
470 |
FPRINTF(ASCERR,"%31s%9x->%9x %9u %6d %s\n","", |
471 |
(unsigned long)adr, |
472 |
(unsigned long)adr + size - 1, |
473 |
size, line, file); |
474 |
} |
475 |
} |
476 |
|
477 |
static void WriteError(CONST char *msg, CONST char *file, int line) |
478 |
{ |
479 |
FPRINTF(ASCERR,"%s\nCalled from file: %s on line %d.\n", msg, file, line); |
480 |
if (NULL != f_memory_log_file) { |
481 |
FPRINTF(f_memory_log_file,"%s\nCalled from file: %s on line %d.\n", |
482 |
msg, file, line); |
483 |
fflush(f_memory_log_file); |
484 |
} |
485 |
} |
486 |
|
487 |
/* |
488 |
* Searches the array of allocation records for ptr. |
489 |
* Returns -1 if no memory records have been recorded. |
490 |
* Otherwise, returns the index of the memory record for |
491 |
* which the stored pointer is greater than or equal to |
492 |
* ptr. If ptr is higher than any of the stored pointers, |
493 |
* then f_memory_length is returned. |
494 |
* |
495 |
* This routine assumes that the memory record array is sorted |
496 |
* by pointer address ascending. |
497 |
*/ |
498 |
static int SearchForMemory(CONST VOIDPTR ptr) |
499 |
{ |
500 |
int c, lower, upper; |
501 |
lower = 0; |
502 |
upper = f_memory_length-1; |
503 |
if (upper<lower) return -1; |
504 |
while(lower<upper){ |
505 |
c = (lower+upper)/2; |
506 |
if (f_mem_rec[c].ptr == ptr) return c; |
507 |
if (f_mem_rec[c].ptr > ptr) |
508 |
upper = c-1; |
509 |
else |
510 |
lower = c+1; |
511 |
} |
512 |
if (upper<lower) return lower; |
513 |
if (lower>upper) return upper; |
514 |
while(( lower < f_memory_length ) && ( f_mem_rec[lower].ptr < ptr )) lower++; |
515 |
return lower; |
516 |
} |
517 |
|
518 |
int AllocatedMemoryF(CONST VOIDPTR ptr, size_t size) |
519 |
{ |
520 |
int pos; |
521 |
|
522 |
if (NULL == ptr) /* NULL ptr - by definition not allocated */ |
523 |
return 0; |
524 |
|
525 |
pos = SearchForMemory(ptr); |
526 |
|
527 |
if (pos < 0) /* no allocation records have been stored */ |
528 |
return 0; |
529 |
|
530 |
/* if a matching pointer was found... */ |
531 |
if (( pos < f_memory_length ) && |
532 |
( f_mem_rec[pos].ptr == ptr )) { |
533 |
if ( f_mem_rec[pos].size == size ) |
534 |
return 2; /* the block matches an allocated block */ |
535 |
if ( f_mem_rec[pos].size > size ) |
536 |
return 1; /* the block is contained in an allocated block */ |
537 |
return -1; /* the block spans multiple allocated blocks */ |
538 |
} |
539 |
|
540 |
/* if ptr block extends into the block above... */ |
541 |
else if (( pos < f_memory_length ) && |
542 |
((CONST VOIDPTR)((CONST char *)ptr + size - 1) >= f_mem_rec[pos].ptr)) { |
543 |
return -1; /* the block extends into the block above */ |
544 |
} |
545 |
|
546 |
else if (pos > 0) { |
547 |
if (ptr > ((CONST VOIDPTR)((CONST char *)f_mem_rec[pos-1].ptr + f_mem_rec[pos-1].size - 1))) |
548 |
return 0; /* ptr not contained within the found block */ |
549 |
|
550 |
if ((CONST VOIDPTR)((CONST char *)ptr + size) |
551 |
<= (CONST VOIDPTR)((CONST char *)f_mem_rec[pos-1].ptr + f_mem_rec[pos-1].size)) |
552 |
return 1; /* the block is contained in an allocated block */ |
553 |
else |
554 |
return -1; /* the block spans multiple allocated blocks */ |
555 |
} |
556 |
|
557 |
return 0; |
558 |
} |
559 |
|
560 |
static void AddAllocatedMemory(CONST VOIDPTR ptr, size_t size, |
561 |
CONST char *file, int line) |
562 |
{ |
563 |
int pos,c; |
564 |
pos = SearchForMemory(ptr); |
565 |
if (( pos < 0 ) || |
566 |
( pos == f_memory_length) || |
567 |
( f_mem_rec[pos].ptr != ptr )) { |
568 |
if ( pos < 0 ) pos = 0; |
569 |
if ( (f_memory_length + 1) < MAXPOINTERS ) { |
570 |
if ( pos == f_memory_length ) { |
571 |
f_memory_length++; |
572 |
f_mem_rec[pos].ptr = ptr; |
573 |
f_mem_rec[pos].size = size; |
574 |
} |
575 |
else { |
576 |
/* make room for the new addition */ |
577 |
for(c=f_memory_length ; c>pos ; c--){ |
578 |
f_mem_rec[c] = f_mem_rec[c-1]; |
579 |
} |
580 |
f_memory_length++; |
581 |
f_mem_rec[pos].ptr = ptr; |
582 |
f_mem_rec[pos].size = size; |
583 |
} |
584 |
} |
585 |
else { |
586 |
FPRINTF(ASCERR, "Pointer list filled up. Error messages may be unreliable.\n"); |
587 |
} |
588 |
} |
589 |
WriteAllocation(ptr,size,file,line); |
590 |
} |
591 |
|
592 |
static void DeallocateMemory(CONST VOIDPTR ptr, size_t size, |
593 |
CONST char *file, int line) |
594 |
{ |
595 |
int pos,c; |
596 |
pos = SearchForMemory(ptr); |
597 |
if (( pos >= 0 ) && |
598 |
( pos < f_memory_length ) && |
599 |
( f_mem_rec[pos].ptr == ptr )) { |
600 |
/* a matching pointer was found */ |
601 |
asc_assert(f_mem_rec[pos].size == size); |
602 |
/* copy all allocation records to the previous index, overwriting the current record */ |
603 |
for(c=pos+1 ; c<f_memory_length ; c++) |
604 |
f_mem_rec[c-1] = f_mem_rec[c]; |
605 |
f_memory_length--; |
606 |
} |
607 |
WriteDeallocation(ptr,size,file,line); |
608 |
} |
609 |
|
610 |
static void ReallocateMemory(CONST VOIDPTR ptr1, size_t size1, |
611 |
CONST VOIDPTR ptr2, size_t size2, |
612 |
CONST char *file, int line) |
613 |
{ |
614 |
int pos,c; |
615 |
/* handle the deallocation first */ |
616 |
pos = SearchForMemory(ptr1); |
617 |
if (( pos >= 0 ) && |
618 |
( pos < f_memory_length ) && |
619 |
( f_mem_rec[pos].ptr == ptr1 )) { |
620 |
/* a matching pointer was found */ |
621 |
asc_assert(f_mem_rec[pos].size == size1); |
622 |
/* copy all allocation records to the previous index, overwriting the current record */ |
623 |
for(c=pos+1 ; c<f_memory_length ; c++) |
624 |
f_mem_rec[c-1] = f_mem_rec[c]; |
625 |
f_memory_length--; |
626 |
} |
627 |
/* then, handle the allocation if ptr2 is non-NULL */ |
628 |
pos = SearchForMemory(ptr2); |
629 |
if (( NULL != ptr2 ) && |
630 |
(( pos < 0 ) || |
631 |
( pos == f_memory_length) || |
632 |
( f_mem_rec[pos].ptr != ptr2 ))) { |
633 |
if ( pos < 0 ) pos = 0; |
634 |
if ( (f_memory_length + 1) < MAXPOINTERS ) { |
635 |
if ( pos == f_memory_length ) { |
636 |
f_memory_length++; |
637 |
f_mem_rec[pos].ptr = ptr2; |
638 |
f_mem_rec[pos].size = size2; |
639 |
} |
640 |
else { |
641 |
/* make room for the new addition */ |
642 |
for(c=f_memory_length ; c>pos ; c--){ |
643 |
f_mem_rec[c] = f_mem_rec[c-1]; |
644 |
} |
645 |
f_memory_length++; |
646 |
f_mem_rec[pos].ptr = ptr2; |
647 |
f_mem_rec[pos].size = size2; |
648 |
} |
649 |
} |
650 |
else { |
651 |
FPRINTF(ASCERR, "Pointer list filled up. Error messages may be unreliable.\n"); |
652 |
} |
653 |
} |
654 |
WriteReAllocation(ptr1,size1,ptr2,size2,file,line); |
655 |
} |
656 |
|
657 |
VOIDPTR asccallocf(size_t nelem, size_t elsize, |
658 |
CONST char *file, int line) |
659 |
{ |
660 |
VOIDPTR result; |
661 |
OpenLogFile(); |
662 |
result = calloc(nelem,elsize); |
663 |
if (NULL != result) { |
664 |
/* adjust statistical variables */ |
665 |
f_memory_allocated += nelem*elsize; |
666 |
if (f_memory_allocated > f_peak_memory_usage) |
667 |
f_peak_memory_usage = f_memory_allocated; |
668 |
if (AllocatedMemory(result,nelem*elsize)){ |
669 |
WriteError("calloc returned a piece of memory that is already being used.", |
670 |
file,line); |
671 |
} |
672 |
AddAllocatedMemory(result,nelem*elsize,file,line); |
673 |
} |
674 |
return result; |
675 |
} |
676 |
|
677 |
VOIDPTR ascmallocf(size_t size, CONST char *file, int line) |
678 |
{ |
679 |
VOIDPTR result; |
680 |
OpenLogFile(); |
681 |
result = malloc(size); |
682 |
if (NULL != result) { |
683 |
f_memory_allocated += size; |
684 |
if (f_memory_allocated > f_peak_memory_usage) |
685 |
f_peak_memory_usage = f_memory_allocated; |
686 |
if (AllocatedMemory(result,size)){ |
687 |
WriteError("malloc returned a piece of memory that is already being used.", |
688 |
file,line); |
689 |
} |
690 |
AddAllocatedMemory(result,size,file,line); |
691 |
}else{ |
692 |
FPRINTF(ASCERR,"ASCMALLOC FAILED TO ALLOCATE MEMORY OF SIZE %d, result=%p\n",size,result); |
693 |
} |
694 |
return result; |
695 |
} |
696 |
|
697 |
static size_t FindMemorySize(CONST VOIDPTR ptr, int * CONST found) |
698 |
{ |
699 |
int pos; |
700 |
pos = SearchForMemory(ptr); |
701 |
if (( pos >= 0 ) && |
702 |
( pos < f_memory_length)) { |
703 |
*found = 1; |
704 |
if (f_mem_rec[pos].ptr==ptr) return f_mem_rec[pos].size; |
705 |
} |
706 |
*found = 0; |
707 |
return 0; |
708 |
} |
709 |
|
710 |
VOIDPTR ascreallocf(VOIDPTR ptr, size_t size, CONST char *file, int line) |
711 |
{ |
712 |
size_t old_size; |
713 |
int found; |
714 |
VOIDPTR result; |
715 |
OpenLogFile(); |
716 |
if (AllocatedMemory(ptr,0)){ |
717 |
old_size = FindMemorySize(ptr,&found); |
718 |
if (!found){ |
719 |
FPRINTF(ASCERR,"realloc'ing a piece of an allocated block.\n"); |
720 |
} |
721 |
result = realloc(ptr,size); |
722 |
} |
723 |
else{ |
724 |
old_size = 0; |
725 |
if (ptr == NULL) { |
726 |
result = malloc(size); |
727 |
} else { |
728 |
WriteError("ascreallocf called on a deallocated piece of memory.", |
729 |
file, line); |
730 |
result = realloc(ptr,size); |
731 |
} |
732 |
} |
733 |
if (NULL == result) |
734 |
size = 0; |
735 |
ReallocateMemory(ptr,old_size,result,size,file,line); |
736 |
if (size >= old_size) |
737 |
f_memory_allocated += (size-old_size); |
738 |
else |
739 |
f_memory_allocated -= (old_size-size); |
740 |
if (f_memory_allocated > f_peak_memory_usage) |
741 |
f_peak_memory_usage = f_memory_allocated; |
742 |
return result; |
743 |
} |
744 |
|
745 |
void ascfreef(VOIDPTR ptr, CONST char *file, int line) |
746 |
{ |
747 |
size_t size; |
748 |
int found; |
749 |
|
750 |
if (NULL == ptr) |
751 |
return; |
752 |
|
753 |
OpenLogFile(); |
754 |
if (0 != AllocatedMemory(ptr,0)) { |
755 |
size = FindMemorySize(ptr,&found); |
756 |
if (!found){ /* indicates a problem */ |
757 |
WriteError("Deallocating a piece of an allocated block.", file, line); |
758 |
} |
759 |
else |
760 |
memset((char *)ptr, 0, size); /* clear the memory */ |
761 |
} |
762 |
else { |
763 |
WriteError("ascfreef called on a deallocated piece of memory.", file, line); |
764 |
size = 0; |
765 |
} |
766 |
DeallocateMemory(ptr,size,file,line); |
767 |
f_memory_allocated -= size; |
768 |
free(ptr); |
769 |
} |
770 |
|
771 |
VOIDPTR ascbcopyf(CONST VOIDPTR src, VOIDPTR dest, size_t length, |
772 |
CONST char *file, int line) |
773 |
{ |
774 |
UNUSED_PARAMETER(file); |
775 |
UNUSED_PARAMETER(line); |
776 |
OpenLogFile(); |
777 |
return memcpy(dest, src, length); |
778 |
} |
779 |
|
780 |
VOIDPTR ascbzerof(VOIDPTR dest, size_t length, CONST char *file, int line) |
781 |
{ |
782 |
UNUSED_PARAMETER(file); |
783 |
UNUSED_PARAMETER(line); |
784 |
OpenLogFile(); |
785 |
return memset((char *)dest, 0, length); |
786 |
} |
787 |
|
788 |
int InMemoryBlockF(CONST VOIDPTR ptr1, CONST VOIDPTR ptr2) |
789 |
{ |
790 |
int pos; |
791 |
pos = SearchForMemory(ptr1); |
792 |
if (( pos >= 0 ) && |
793 |
( pos < f_memory_length ) && |
794 |
( f_mem_rec[pos].ptr == ptr1 )) |
795 |
return (( ptr2 >= ptr1 ) && |
796 |
( ptr2 < (CONST VOIDPTR)((CONST char *)ptr1 + f_mem_rec[pos].size))); |
797 |
else |
798 |
return 0; |
799 |
} |