Macaulay2 Engine
Loading...
Searching...
No Matches
m2-mem.cpp
Go to the documentation of this file.
1#include <stdio.h>
2#include <unistd.h>
3#include <M2/gc-include.h>
4#include <M2/config.h>
5
6#include "m2-mem.h"
7
8/* #ifdef MEMDEBUG */
9/* #include <memdebug.h> */
10/* #endif */
11
12#ifndef NDEBUG
13#define __thread
14static __thread bool in_getmem = false;
15static inline void enter_getmem() {
16 #if 0
17 /* this is not always an error, because we may call GC_malloc from a finalizer */
18 if (in_getmem) fatal("internal error: getmem called while getmem active");
19 #endif
20 in_getmem = true;
21}
22static inline void exit_getmem() {
23 in_getmem = false;
24}
25#else
26static inline void enter_getmem() {}
27static inline void exit_getmem() {}
28#endif
29
30/* trapchk: taken from d/debug.h *************************************/
31
32void *trapaddr = (void *)1;
33int trapcount = 0;
34int trapset = 0;
35size_t trapsize = (size_t)-1;
36
37void trap(void) {} /* I used to be concerned that this function would get optimized away, but it isn't static ... */
38
39void *pointers[10]; /* during debugging we can put pointers here, visible to the garbage collector */
40void trapchk(void *p) {
41 trapcount++;
42 if (trapcount == trapset || p == trapaddr || p == (void *)~(intptr_t)trapaddr) trap();
43}
44void trapchk_size(size_t n) {
45 trapcount++;
46 if (trapcount == trapset || trapsize == n) trap();
47}
48
49/*********************************************************************/
50
51// taken from d/types.h
52const int STDIN = 0;
53const int STDOUT = 1;
54const int STDERR = 2;
55const int ERROR = -1;
56
57void outofmem(void) {
58 const char *msg = "\n\n *** out of memory, exiting ***\n";
59 int r = write(STDERR,msg,strlen(msg));
60 if (r == ERROR) exit(1);
61 exit(1);
62}
63
64void outofmem2(size_t newsize) {
65 const char *msg = "\n\n *** out of memory trying to allocate %ld bytes, exiting ***\n";
66 static char buf[sizeof(msg) + 100];
67 snprintf(buf, sizeof(msg) + 100,
68 msg, (long)newsize);
69 int r = write(STDERR,buf,strlen(buf));
70 if (r == ERROR) exit(1);
71 exit(1);
72}
73
74char *getmem(size_t n)
75{
76 char *p;
77 TRAPCHK_SIZE(n);
79#ifdef MEMDEBUG
80 p = M2_debug_malloc(n);
81#else
82 p = reinterpret_cast<char*>(GC_MALLOC(n)); /* GC_MALLOC clears its memory; we preserve that */
83#endif
84 if (p == NULL) outofmem2(n);
85#ifndef NDEBUG
86 memset(p,0xbe,n); /* fill with 0xbebebebe ... */
87 trapchk(p);
88#endif
90 return p;
91}
92
93void freememlen(void *s, size_t old) {
94 (void)old;
95 TRAPCHK(s);
96#ifdef MEMDEBUG
97 M2_debug_free(s);
98#else
99 /* GC_FREE(s); */
100#endif
101}
102
103void freemem(void *s) {
104 TRAPCHK(s);
105#ifdef MEMDEBUG
106 M2_debug_free(s);
107#else
108 /* GC_FREE(s); */
109#endif
110}
111
112char *getmem_clear(size_t n)
113{
114 char *p;
115 enter_getmem();
116#ifdef MEMDEBUG
117 p = M2_debug_malloc(n);
118#else
119 p = reinterpret_cast<char*>(GC_MALLOC(n));
120#endif
121 if (p == NULL) outofmem2(n);
122#ifdef MEMDEBUG
123 memset(p,0,n);
124#else
125 /* note: GC_MALLOC clears memory before returning.
126 If you switch to another memory allocator, you must clear it explicitly here */
127#endif
128 #ifndef NDEBUG
129 trapchk(p);
130 #endif
131 exit_getmem();
132 return p;
133}
134
135char *getmem_atomic(size_t n)
136{
137 char *p;
138 enter_getmem();
139#ifdef MEMDEBUG
140 p = M2_debug_malloc_atomic(n);
141#else
142 p = reinterpret_cast<char*>(GC_MALLOC_ATOMIC(n));
143#endif
144 if (p == NULL) outofmem2(n);
145#ifndef NDEBUG
146 memset(p,0xac,n); /* fill with 0xacacacac ... */
147 trapchk(p);
148#endif
149 exit_getmem();
150 return p;
151}
152
153// char *getmem_malloc(size_t n)
154// {
155// char *p;
156// enter_getmem();
157// p = malloc(n);
158// if (p == NULL) outofmem2(n);
159// #ifndef NDEBUG
160// memset(p,0xca,n); /* fill with 0xcacacaca */
161// trapchk(p);
162// #endif
163// exit_getmem();
164// return p;
165// }
166
167char *getmem_atomic_clear(size_t n)
168{
169 char *p;
170 enter_getmem();
171#ifdef MEMDEBUG
172 p = M2_debug_malloc_atomic(n);
173#else
174 p = reinterpret_cast<char*>(GC_MALLOC_ATOMIC(n));
175#endif
176 if (p == NULL) outofmem2(n);
177 memset(p,0,n); /* GC_MALLOC_ATOMIC does not clear memory */
178#ifndef NDEBUG
179 trapchk(p);
180#endif
181 exit_getmem();
182 return p;
183}
184
185// char *getmoremem (char *s, size_t old, size_t newsize) {
186// void *p;
187// enter_getmem();
188// p = reinterpret_cast<char*>(GC_REALLOC(s,newsize));
189// if (p == NULL) outofmem2(newsize);
190// # ifndef NDEBUG
191// trapchk(p);
192// # endif
193// exit_getmem();
194// return reinterpret_cast<char*>(p);
195// }
196
197// char *getmoremem1 (char *s, size_t newsize) {
198// void *p;
199// enter_getmem();
200// p = reinterpret_cast<char*>(GC_REALLOC(s,newsize));
201// if (p == NULL) outofmem2(newsize);
202// # ifndef NDEBUG
203// trapchk(p);
204// # endif
205// exit_getmem();
206// return reinterpret_cast<char*>(p);
207// }
208
209// char *getmoremem_atomic (char *s, size_t old, size_t newsize) {
210// void *p;
211// enter_getmem();
212// #ifdef MEMDEBUG
213// p = M2_debug_malloc_atomic(newsize);
214// #else
215// p = reinterpret_cast<char*>(GC_MALLOC_ATOMIC(newsize));
216// #endif
217// size_t min = old<newsize ? old : newsize;
218// if (p == NULL) outofmem2(newsize);
219// memcpy(p, s, min);
220// /* GC_FREE(s); */
221// # ifndef NDEBUG
222// {
223// int excess = newsize - min;
224// if (excess > 0) memset((char *)p+min,0xbe,excess); /* fill with 0xbebebebe */
225// }
226// trapchk(p);
227// # endif
228// exit_getmem();
229// return reinterpret_cast<char*>(p);
230// }
231
232/* Valgrind helper functions */
233#ifndef NVALGRIND
234
235void *I_WRAP_SONAME_FNNAME_ZU(libgcZdsoZd1,GC_malloc)(size_t s){
236 long result;
237 OrigFn fn;
239 CALL_FN_W_W(result,fn,s);
240 VALGRIND_MAKE_MEM_DEFINED(&result,sizeof(result));
241 return (void*)result;
242}
243
244void *I_WRAP_SONAME_FNNAME_ZU(libgcZdsoZd1,GC_malloc_atomic)(size_t s){
245 long result;
246 OrigFn fn;
248 CALL_FN_W_W(result,fn,s);
249 VALGRIND_MAKE_MEM_DEFINED(&result,sizeof(result));
250 return (void*)result;
251}
252
253void *I_WRAP_SONAME_FNNAME_ZU(libgcZdsoZd1,GC_malloc_ignore_off_page)(size_t s){
254 long result;
255 OrigFn fn;
257 CALL_FN_W_W(result,fn,s);
258 VALGRIND_MAKE_MEM_DEFINED(&result,sizeof(result));
259 return (void*)result;
260}
261
262void *I_WRAP_SONAME_FNNAME_ZU(libgcZdsoZd1,GC_malloc_atomic_ignore_off_page)(size_t s){
263 long result;
264 OrigFn fn;
266 CALL_FN_W_W(result,fn,s);
267 VALGRIND_MAKE_MEM_DEFINED(&result,sizeof(result));
268 return (void*)result;
269}
270
271void *I_WRAP_SONAME_FNNAME_ZU(libgcZdsoZd1,GC_realloc)(void *p, size_t s){
272 long result;
273 OrigFn fn;
276 VALGRIND_MAKE_MEM_DEFINED(&result,sizeof(result));
277 return (void*)result;
278}
279
280#endif /* NVALGRIND */
281
282#ifdef MEMDEBUG
283
284/* note: the debugging facilities in this file partially conflict with
285 the debugging facilities gc.h provides, since when DEBUG is
286 defined, it records the location of the calls to GC_malloc. In
287 fact, we bypass their debugging entirely, by calling the functions
288 instead of the macros.
289*/
290
291/*
292
293 Here is how you might use this. (Turn it on by configuring with --enable-memdebug.)
294
295 (gdb) run
296 Starting program: /home/dan/local/src/M2/tmp/Macaulay2/bin/M2 -q --no-loaddata
297 [New Thread 16384 (LWP 5498)]
298 [Switching to Thread 16384 (LWP 5498)]
299
300 Breakpoint 1, trap () at ../../../Macaulay2/d/debug.c:7
301
302 We always set a breakpoint in trap().
303
304 I want to look at the millionth memory allocation:
305
306 (gdb) set trapset=1000000
307
308 (gdb) c
309 Continuing.
310 Macaulay 2, version 0.9.5
311 --package Main installed
312
313 Breakpoint 1, trap () at ../../../Macaulay2/d/debug.c:7
314 (gdb) up
315 #1 0x0804d7d9 in trapchk (p=0x998cfd0) at ../../../Macaulay2/d/debug.c:11
316 (gdb) up
317 #2 0x08050b88 in M2_debug_malloc_atomic (size=19)
318 at ../../../Macaulay2/d/memdebug.c:110
319 (gdb) up
320 #3 0x0804df20 in getmem_atomic (n=19) at ../../../Macaulay2/d/M2mem.c:34
321 (gdb) up
322 #4 0x0804dd86 in strings_join (x=0x83dde80, y=0x9cf54e0)
323 at ../../../Macaulay2/d/M2types.c:119
324 (gdb) up
325 #5 0x08118521 in strings_plus_ (s_1=0x83dde80, t=0x9cf54e0) at strings.d:21
326 (gdb) up
327 #6 0x0809ff29 in presentfun (e_33={type_ = 34, ptr_ = 0x9cf54e0})
328 at actors4.d:820
329 (gdb) up
330 #7 0x080d0441 in evaluate_apply_4 (f_12={type_ = 5, ptr_ = 0x83e08b0}, e_1=
331 {type_ = 34, ptr_ = 0x9cf54e0}) at evaluate.d:585
332
333 Let's say I'm suddenly interested in this pointer, f_12;
334
335 I have a routine that will tell me the size of the memory area:
336
337 (gdb) p M2_debug_size(f_12.ptr_)
338 $2 = 8
339
340 and a variable that tells how bytes are appended in front
341
342 (gdb) p front
343 $3 = 16
344
345 and in the rear:
346
347 (gdb) p rear
348 $4 = 16
349
350 So now look at memory, including the two fences:
351
352 (gdb) x/10x f_12.ptr_-front
353 0x83e08a0: 0x00001193 0x00000008 0xaaaaaaaa 0xaaaaaaaa
354 0x83e08b0: 0x0809fed0 0x000f43e5 0xcccccccc 0xcccccccc
355 0x83e08c0: 0x00000008 0x00001193
356
357 The words 0xaaaaaaaa are the (intact) fence words in front, and the
358 words 0xcccccccc are the fence words behind, while the memory is
359 active. They get changed to 0xa0a0a0a0 and to 0xc0c0c0c0 when the
360 memory is freed.
361
362 The data bytes themselves are initialized to 0xbbbbbbbb upon
363 allocation, and changed to 0xb0b0b0b0 when the memory is freed.
364
365 The two copies of 0x00001193 are the sequence number, and the two
366 copies of 0x00000008 are the size. They should agree.
367
368*/
369
370#include <M2/config.h>
371#include <M2/gc-include.h>
372#include <stdio.h>
373#include <unistd.h>
374#include <string.h>
375//#define MEMDEBUG_INTERNAL
376
377#define FREE_DELAY 10
378#define FENCE_INTS 2
379#define FRONT_FENCE 0xaaaaaaaa
380#define FRONT_FENCE_GONE 0xa0a0a0a0
381#define BODY_PART 0xbbbbbbbb
382#define BODY_PART_GONE 0xb0b0b0b0
383#define REAR_FENCE 0xcccccccc
384#define REAR_FENCE_GONE 0xc0c0c0c0
385
386struct FRONT {
387 int trapcount;
388 size_t size;
389 unsigned int fence[FENCE_INTS];
390 };
391
392struct REAR {
393 unsigned int fence[FENCE_INTS];
394 size_t size;
395 int trapcount;
396 };
397
398
399
400
401void *delay_chain[FREE_DELAY];
402int delay_chain_index;
403
404size_t M2_debug_size(void *p) {
405 struct FRONT *f;
406 if (p == NULL) return 0;
407 f = (struct FRONT *)(p - sizeof(struct FRONT));
408 return f->size;
409}
410
411void *M2_debug_malloc(size_t size) {
412 struct FRONT *f;
413 char *p;
414 struct REAR *r;
415 int i;
416 int INTS_BODY = (size + sizeof(int) - 1)/sizeof(int);
417 f = (struct FRONT *)GC_MALLOC( sizeof(struct FRONT) + sizeof(int)*INTS_BODY + sizeof(struct REAR) );
418 if (f == NULL) outofmem2(size);
419 p = (char *)f + sizeof(struct FRONT);
420 r = (struct REAR *)(p + sizeof(int)*INTS_BODY);
421 f->size = r->size = size;
422 for (i=0; i<FENCE_INTS; i++) f->fence[i] = FRONT_FENCE;
423 for (i=0; i<INTS_BODY; i++) ((int *)p)[i] = BODY_PART;
424 for (i=0; i<FENCE_INTS; i++) r->fence[i] = REAR_FENCE;
425 f->trapcount = r->trapcount = trapcount+1;
426 trapchk(p); /* trapchk increments trapcount before possibly calling trap() -- set your breakpoint in trap() */
427 return p;
428 }
429
430void* M2_debug_malloc_uncollectable(size_t size) {
431 struct FRONT *f;
432 char *p;
433 struct REAR *r;
434 int i;
435 int INTS_BODY = (size + sizeof(int) - 1)/sizeof(int);
436 f = (struct FRONT *)GC_MALLOC_UNCOLLECTABLE(
437 sizeof(struct FRONT) + sizeof(int)*INTS_BODY + sizeof(struct REAR)
438 );
439 if (f == NULL) outofmem2(size);
440 p = (char *)f + sizeof(struct FRONT);
441 r = (struct REAR *)(p + sizeof(int)*INTS_BODY);
442 f->size = r->size = size;
443 for (i=0; i<FENCE_INTS; i++) f->fence[i] = FRONT_FENCE;
444 for (i=0; i<INTS_BODY; i++) ((int *)p)[i] = BODY_PART;
445 for (i=0; i<FENCE_INTS; i++) r->fence[i] = REAR_FENCE;
446 f->trapcount = r->trapcount = trapcount+1;
447 trapchk(p);
448 return p;
449 }
450
451void* M2_debug_malloc_atomic(size_t size) {
452 struct FRONT *f;
453 char *p;
454 struct REAR *r;
455 int i;
456 int INTS_BODY = (size + sizeof(int) - 1)/sizeof(int);
457 f = (struct FRONT *)GC_MALLOC_ATOMIC( sizeof(struct FRONT) + sizeof(int)*INTS_BODY + sizeof(struct REAR) );
458 if (f == NULL) outofmem2(size);
459 p = (void *)f + sizeof(struct FRONT);
460 r = (struct REAR *)(p + sizeof(int)*INTS_BODY);
461 f->size = r->size = size;
462 for (i=0; i<FENCE_INTS; i++) f->fence[i] = FRONT_FENCE;
463 for (i=0; i<INTS_BODY; i++) ((int *)p)[i] = BODY_PART;
464 for (i=0; i<FENCE_INTS; i++) r->fence[i] = REAR_FENCE;
465 f->trapcount = r->trapcount = trapcount+1;
466 trapchk(p);
467 return p;
468 }
469
470void* M2_debug_malloc_atomic_uncollectable(size_t size) {
471 struct FRONT *f;
472 char *p;
473 struct REAR *r;
474 int i;
475 int INTS_BODY = (size + sizeof(int) - 1)/sizeof(int);
476 f = (struct FRONT *)GC_MALLOC_ATOMIC_UNCOLLECTABLE( sizeof(struct FRONT) + sizeof(int)*INTS_BODY + sizeof(struct REAR) );
477 if (f == NULL) outofmem2(size);
478 p = (void *)f + sizeof(struct FRONT);
479 r = (struct REAR *)(p + sizeof(int)*INTS_BODY);
480 f->size = r->size = size;
481 for (i=0; i<FENCE_INTS; i++) f->fence[i] = FRONT_FENCE;
482 for (i=0; i<INTS_BODY; i++) ((int *)p)[i] = BODY_PART;
483 for (i=0; i<FENCE_INTS; i++) r->fence[i] = REAR_FENCE;
484 f->trapcount = r->trapcount = trapcount+1;
485 trapchk(p);
486 return p;
487 }
488
489static void volatile smashed(void *p) {
490 if (0 == GC_base(p)) {
491 fprintf(stderr,"-- *** memdebug -- non-heap object encountered, %p, aborting\n",p);
492 }
493 else {
494 fprintf(stderr,"-- *** memdebug -- smashed object found, %p, aborting\n",p);
495 }
496 trap();
497 abort();
498 }
499
500void *M2_debug_to_outer(void *p) {
501 struct FRONT *f = p - sizeof(struct FRONT);
502 if (f->fence[0] != FRONT_FENCE) smashed(p);
503 return f;
504 }
505
506
507void *M2_debug_to_inner(void *q) {
508 struct FRONT *f = q;
509 if (f->fence[0] != FRONT_FENCE) smashed(q);
510 return (void *)f + sizeof(struct FRONT);
511 }
512
513void M2_debug_info(void *p) {
514 struct FRONT *f;
515 struct REAR *r;
516 int INTS_BODY, i, smashed = 0;
517 size_t size;
518 if (p == NULL) return;
519 f = p - sizeof(struct FRONT);
520 size = f->size;
521 INTS_BODY = (size + sizeof(int) - 1)/sizeof(int);
522 r = (struct REAR *)(p + sizeof(int)*INTS_BODY);
523 for (i=0; i<FENCE_INTS; i++) if (f->fence[i] != FRONT_FENCE) smashed = 1;
524 for (i=0; i<FENCE_INTS; i++) if (r->fence[i] != REAR_FENCE ) smashed = 1;
525 fprintf(stderr,"addr %p, base %p, GC_base %p, trapcount %d, length %lu%s\n",p,f,GC_base(p),f->trapcount,size,smashed ? ", smashed" : "");
526 }
527
528void M2_debug_free(void *p) {
529 struct FRONT *f;
530 struct REAR *r;
531 int INTS_BODY, i, _trapcount;
532 size_t size;
533 if (p == NULL) return;
534 f = (struct FRONT *)(p - sizeof(struct FRONT));
535 size = f->size;
536 INTS_BODY = (size + sizeof(int) - 1)/sizeof(int);
537 r = p + sizeof(int)*INTS_BODY;
538 _trapcount = f->trapcount;
539 if (r->trapcount != _trapcount || r->size != size) smashed(p);
540 for (i=0; i<FENCE_INTS; i++) if (f->fence[i] != FRONT_FENCE) smashed(p);
541 for (i=0; i<FENCE_INTS; i++) if (r->fence[i] != REAR_FENCE ) smashed(p);
542 if (_trapcount == trapset) trap();
543 trapchk(p);
544 for (i=0; i<FENCE_INTS; i++) f->fence[i] = FRONT_FENCE_GONE;
545 for (i=0; i<INTS_BODY; i++) ((int *)p)[i] = BODY_PART_GONE;
546 for (i=0; i<FENCE_INTS; i++) r->fence[i] = REAR_FENCE_GONE;
547#if FREE_DELAY != 0
548 if (delay_chain[delay_chain_index] != NULL) {
549 GC_FREE(delay_chain[delay_chain_index]);
550 }
551 delay_chain[delay_chain_index] = (void *)f;
552 delay_chain_index ++;
553 if (delay_chain_index == FREE_DELAY) delay_chain_index = 0;
554#else
555 GC_FREE(f);
556#endif
557 }
558
559void* M2_debug_realloc(void *old, size_t size) {
560 void *newsize = M2_debug_malloc(size);
561 size_t oldsize = M2_debug_size(old);
562 if (newsize == NULL) outofmem2(size);
563 memcpy(newsize,old,size < oldsize ? size : oldsize);
564 return newsize;
565 }
566
567#endif /* MEMDEBUG */
568
569/*
570 Local Variables:
571 indent-tabs-mode: nil
572 End:
573*/
int p
void * I_WRAP_SONAME_FNNAME_ZU(libgcZdsoZd1, GC_malloc)(size_t s)
Definition m2-mem.cpp:235
char * getmem_atomic_clear(size_t n)
Definition m2-mem.cpp:167
void freemem(void *s)
Definition m2-mem.cpp:103
const int STDOUT
Definition m2-mem.cpp:53
void * trapaddr
Definition m2-mem.cpp:32
void trapchk(void *p)
Definition m2-mem.cpp:40
void size_t s
Definition m2-mem.cpp:271
void trapchk_size(size_t n)
Definition m2-mem.cpp:44
const int STDIN
Definition m2-mem.cpp:52
void * pointers[10]
Definition m2-mem.cpp:39
int trapset
Definition m2-mem.cpp:34
#define __thread
Definition m2-mem.cpp:13
OrigFn fn
Definition m2-mem.cpp:273
size_t trapsize
Definition m2-mem.cpp:35
int trapcount
Definition m2-mem.cpp:33
CALL_FN_W_WW(result, fn,(long) p, s)
char * getmem(size_t n)
Definition m2-mem.cpp:74
VALGRIND_GET_ORIG_FN(fn)
static __thread bool in_getmem
Definition m2-mem.cpp:14
char * getmem_clear(size_t n)
Definition m2-mem.cpp:112
void freememlen(void *s, size_t old)
Definition m2-mem.cpp:93
static void exit_getmem()
Definition m2-mem.cpp:22
static void enter_getmem()
Definition m2-mem.cpp:15
void outofmem(void)
Definition m2-mem.cpp:57
const int ERROR
Definition m2-mem.cpp:55
void outofmem2(size_t newsize)
Definition m2-mem.cpp:64
char * getmem_atomic(size_t n)
Definition m2-mem.cpp:135
VALGRIND_MAKE_MEM_DEFINED & result(result)
void trap(void)
Definition m2-mem.cpp:37
const int STDERR
Definition m2-mem.cpp:54
#define TRAPCHK_SIZE(n)
Definition m2-mem.h:67
#define TRAPCHK(p)
Definition m2-mem.h:66
void size_t
Definition m2-mem.h:114
Engine-wide GC allocator surface (getmem / getmem_atomic) and debug-allocation trap.