2 * Filippo's charm debug memory module, gioachin@uiuc.edu, 2005/10
3 * based on Orion's memory-leak.c
5 * This special version of malloc() and company is meant to be used in
6 * conjunction with the parallel debugger CharmDebug.
8 * Functionalities provided:
9 * - detect multiple delete on a pointer
10 * - stacktrace for all memory allocated
11 * - division of allocated memory among different types of allocations
12 * - sweep of the memory searching for leaks
15 #if ! CMK_MEMORY_BUILD_OS
16 /* Use Gnumalloc as meta-meta malloc fallbacks (mm_*) */
17 #include "memory-gnu.c"
22 /* Utilities needed by the code */
23 #include "ckhashtable.h"
25 /*#include "pup_c.h" */
30 #error "charmdebug is not enabled (e.g. when building with-production)"
31 static void *meta_malloc(size_t size
);
32 static void *meta_calloc(size_t nelem
, size_t size
);
33 static void *meta_realloc(void *oldBuffer
, size_t newSize
);
34 static void *meta_memalign(size_t align
, size_t size
);
35 static int meta_posix_memalign(void **outptr
, size_t align
, size_t size
);
36 static void *meta_aligned_alloc(size_t align
, size_t size
);
37 static void *meta_valloc(size_t size
);
38 static void *meta_pvalloc(size_t size
);
41 void CmiBacktraceRecordHuge(void **retPtrs
,int *nLevels
);
43 typedef struct _Slot Slot
;
44 typedef struct _SlotStack SlotStack
;
47 extern int memory_chare_id
;
49 int memory_charmdebug_internal
= 0;
52 * Struct Slot contains all of the information about a malloc buffer except
53 * for the contents of its memory.
56 #ifdef CMK_SEPARATE_SLOT
59 /*Doubly-linked allocated block list*/
64 /*The number of bytes of user data*/
67 #define FLAGS_MASK 0xFF
68 #define BLOCK_PROTECTED 0x80
70 #define NEW_BLOCK 0x20
71 #define LEAK_CLEAN 0x10
73 #define UNKNOWN_TYPE 0x0
74 #define SYSTEM_TYPE 0x1
76 #define CHARE_TYPE 0x3
77 #define MESSAGE_TYPE 0x4
78 /* A magic number field, to verify this is an actual malloc'd buffer, and what
79 type of allocation it is. The last 4 bits of the magic number are used to
80 define a classification of mallocs. */
81 #define SLOTMAGIC 0x8402a500
82 #define SLOTMAGIC_VALLOC 0x7402a500
83 #define SLOTMAGIC_FREED 0xDEADBEEF
87 /* Controls the number of stack frames to print out. */
91 /* Pointer to extra stacktrace, when the user requested more trace */
92 SlotStack
*extraStack
;
100 char *protectedMemory
;
101 int protectedMemoryLength
;
102 /* empty for the moment, to be filled when needed */
105 /********* List of allocated memory *********/
107 /* First memory slot */
108 #ifdef CMK_SEPARATE_SLOT
109 CkHashtable_c block_slots
= NULL
;
111 Slot slot_first_storage
= {&slot_first_storage
, &slot_first_storage
};
112 Slot
*slot_first
= &slot_first_storage
;
115 int memory_allocated_user_total
;
116 int get_memory_allocated_user_total() {return memory_allocated_user_total
;}
118 void *lastMemoryAllocated
= NULL
;
119 Slot
**allocatedSince
= NULL
;
120 int allocatedSinceSize
= 0;
121 int allocatedSinceMaxSize
= 0;
122 int saveAllocationHistory
= 0;
124 /* Convert a slot to a user address */
125 static char *SlotToUser(Slot
*s
) {
126 #ifdef CMK_SEPARATE_SLOT
129 return ((char *)s
)+sizeof(Slot
);
134 /* Convert a user address to a slot. The parameter "user" must be at the
135 * beginning of the allocated block */
136 static Slot
*UserToSlot(void *user
) {
137 #ifdef CMK_SEPARATE_SLOT
138 return (Slot
*)CkHashtableGet(block_slots
, &user
);
140 char *cu
=(char *)user
;
141 Slot
*s
=(Slot
*)(cu
-sizeof(Slot
));
146 static int isLeakSlot(Slot
*s
) {
147 return s
->magic
& LEAK_FLAG
;
150 static int isProtected(Slot
*s
) {
151 return s
->magic
& BLOCK_PROTECTED
;
155 int Slot_ChareOwner(void *s
) {
156 return ((Slot
*)s
)->chareID
;
159 int Slot_AllocatedSize(void *s
) {
160 return ((Slot
*)s
)->userSize
;
164 int Slot_StackTrace(void *s
, void ***stack
) {
165 *stack
= ((Slot
*)s
)->from
;
166 return ((Slot
*)s
)->stackLen
;
169 static void printSlot(Slot
*s
) {
170 CmiPrintf("[%d] Leaked block of %d bytes at %p:\n",
171 CmiMyPe(), s
->userSize
, (void *)SlotToUser(s
));
172 CmiBacktracePrint(s
->from
,s
->stackLen
);
175 /********* Cpd routines for pupping data to the debugger *********/
177 /** Returns the number of total blocks of memory allocated */
179 size_t cpd_memory_length(void *lenParam
) {
181 #ifdef CMK_SEPARATE_SLOT
182 n
= CkHashtableSize(block_slots
) - 1;
184 Slot
*cur
= slot_first
->next
;
185 while (cur
!= slot_first
) {
193 /** PUP a single slot of memory for the debugger. This includes the information
194 * about the slot (like size and location), but not the allocated data itself. */
195 #ifdef CMK_SEPARATE_SLOT
196 void cpd_memory_single_pup(CkHashtable_c h
, pup_er p
) {
197 CkHashtableIterator_c hashiter
;
202 memory_charmdebug_internal
= 1;
203 hashiter
= CkHashtableGetIterator(h
);
204 while ((cur
= (Slot
*)CkHashtableIteratorNext(hashiter
, &key
)) != NULL
) {
205 if (pup_isPacking(p
) && cur
->userData
== lastMemoryAllocated
) continue;
208 void cpd_memory_single_pup(Slot
* list
, pup_er p
) {
209 Slot
*cur
= list
->next
;
210 /* Stupid hack to avoid sending the memory we just allocated for this packing,
211 otherwise the lengths will mismatch */
212 if (pup_isPacking(p
)) cur
= cur
->next
;
213 for ( ; cur
!= list
; cur
= cur
->next
) {
218 void *loc
= SlotToUser(cur
);
219 CpdListBeginItem(p
, 0);
220 pup_comment(p
, "loc");
221 pup_pointer(p
, &loc
);
222 pup_comment(p
, "size");
223 pup_int(p
, &cur
->userSize
);
224 pup_comment(p
, "flags");
225 flags
= cur
->magic
& FLAGS_MASK
;
227 pup_comment(p
, "chare");
228 pup_int(p
, &cur
->chareID
);
229 pup_comment(p
, "stack");
230 //for (i=0; i<STACK_LEN; ++i) {
231 // if (cur->from[i] <= 0) break;
232 // if (cur->from[i] > 0) pup_uint(p, (unsigned int*)&cur->from[i]);
235 if (cur
->from
!= NULL
)
236 pup_pointers(p
, cur
->from
, cur
->stackLen
);
239 printf("Block %p has no stack!\n",(void *)cur
);
240 pup_pointer(p
, &myNULL
);
244 /*CmiPrintf("counter=%d\n",counter);*/
245 memory_charmdebug_internal
= 0;
248 /** PUP the entire information about the allocated memory to the debugger */
250 void cpd_memory_pup(void *itemParam
, pup_er p
, CpdListItemsRequest
*req
) {
251 static char s_memory
[] = "memory";
252 CpdListBeginItem(p
, 0);
253 pup_comment(p
, "name");
254 pup_chars(p
, s_memory
, sizeof(s_memory
)-1);
255 pup_comment(p
, "slots");
256 pup_syncComment(p
, pup_sync_begin_array
, 0);
257 #ifdef CMK_SEPARATE_SLOT
258 cpd_memory_single_pup(block_slots
, p
);
260 cpd_memory_single_pup(slot_first
, p
);
262 pup_syncComment(p
, pup_sync_end_array
, 0);
267 void check_memory_leaks(CpdListItemsRequest *);
269 void cpd_memory_leak(void *iterParam, pup_er p, CpdListItemsRequest *req) {
270 if (pup_isSizing(p)) {
271 // let's perform the memory leak checking. This is the first step in the
272 // packing, where we size, in the second step we pack and we avoid doing
274 check_memory_leaks(req);
276 cpd_memory_pup(iterParam, p, req);
281 size_t cpd_memory_getLength(void *lenParam
) { return 1; }
282 /** Returns the content of a block of memory (i.e the user data).
283 This request must always be at the beginning of an allocated block
284 (not for example an object part of an array) */
286 void cpd_memory_get(void *iterParam
, pup_er p
, CpdListItemsRequest
*req
) {
287 void *userData
= (void*)(uintptr_t)(((uint64_t)req
->lo
) + (((uint64_t)req
->hi
)<<32));
288 Slot
*sl
= UserToSlot(userData
);
289 CpdListBeginItem(p
, 0);
290 pup_comment(p
, "size");
291 //printf("value: %x %x %x %d\n",sl->magic, sl->magic&~FLAGS_MASK, SLOTMAGIC, ((sl->magic&~FLAGS_MASK) != SLOTMAGIC));
292 if ((sl
->magic
&~FLAGS_MASK
) != SLOTMAGIC
) {
296 pup_int(p
, &sl
->userSize
);
297 pup_comment(p
, "value");
298 pup_bytes(p
, userData
, sl
->userSize
);
302 /********* Heap Checking ***********/
304 int charmEnvelopeSize
= 0;
308 #ifdef CMK_SEPARATE_SLOT
310 #define SLOT_ITERATE_START(scanner) \
312 CkHashtableIterator_c hashiter = CkHashtableGetIterator(block_slots); \
314 while ((scanner = (Slot *)CkHashtableIteratorNext(hashiter, &key)) != NULL) {
315 #define SLOT_ITERATE_END \
317 CkHashtableDestroyIterator(hashiter); \
320 #define SLOTSPACE sizeof(Slot)
321 #define SLOT_ITERATE_START(scanner) \
322 for (scanner=slot_first->next; scanner!=slot_first; scanner=scanner->next) {
323 #define SLOT_ITERATE_END }
326 /** Perform a scan of all the memory to find all the memory that is reacheable
327 * from either the stack or the global variables. */
328 // FIXME: this function assumes that all memory is allocated in slot_unknown!
330 void check_memory_leaks(LeakSearchInfo
*info
) {
331 //FILE* fd=fopen("check_memory_leaks", "w");
333 // index all memory into a CkHashtable, with a scan of 4 bytes.
336 Slot
*sl
, **fnd
, *found
;
338 char *begin_stack
, *end_stack
;
339 //char *begin_data, *end_data;
340 //char *begin_bss, *end_bss;
341 int growing_dimension
= 0;
343 // copy all the memory from "slot_first" to "leaking"
345 Slot
*slold1
=0, *slold2
=0, *slold3
=0;
347 memory_charmdebug_internal
= 1;
349 inProgress
= PCQueueCreate();
350 table
= CkCreateHashtable_pointer(sizeof(char *), 10000);
351 SLOT_ITERATE_START(sl
)
352 // index the i-th memory slot
353 //printf("hashing slot %p\n",sl);
355 sl
->magic
|= LEAK_FLAG
;
356 if (info
->quick
> 0) {
358 //CmiPrintf("checking memory fast\n");
359 // means index only specific offsets of the memory region
360 ptr
= SlotToUser(sl
);
361 object
= (char**)CkHashtablePut(table
, &ptr
);
364 object
= (char**)CkHashtablePut(table
, &ptr
);
366 // beginning of converse header
367 ptr
+= sizeof(CmiChunkHeader
) - 4;
368 if (ptr
< SlotToUser(sl
)+sizeof(Slot
)+sl
->userSize
) {
369 object
= (char**)CkHashtablePut(table
, &ptr
);
372 // beginning of charm header
373 ptr
+= CmiReservedHeaderSize
;
374 if (ptr
< SlotToUser(sl
)+sizeof(Slot
)+sl
->userSize
) {
375 object
= (char**)CkHashtablePut(table
, &ptr
);
378 // beginning of ampi header
379 ptr
+= charmEnvelopeSize
- CmiReservedHeaderSize
;
380 if (ptr
< SlotToUser(sl
)+sizeof(Slot
)+sl
->userSize
) {
381 object
= (char**)CkHashtablePut(table
, &ptr
);
385 //CmiPrintf("checking memory extensively\n");
386 // means index every fourth byte of the memory region
387 for (ptr
= SlotToUser(sl
); ptr
<= SlotToUser(sl
)+sl
->userSize
; ptr
+=sizeof(char*)) {
388 //printf("memory %p\n",ptr);
389 //growing_dimension++;
390 //if ((growing_dimension&0xFF) == 0) printf("inserted %d objects\n",growing_dimension);
391 char **object
= (char**)CkHashtablePut(table
, &ptr
);
401 // start the check with the stack and the global data. The stack is found
402 // through the current pointer, going up until 16 bits filling (considering
403 // the stack grows toward decreasing addresses). The pointers to the global
404 // data (segments .data and .bss) are passed in with "req" as the "extra"
405 // field, with the structure "begin .data", "end .data", "begin .bss", "end .bss".
406 begin_stack
= (char*)&table
;
407 end_stack
= (char*)memory_stack_top
;
408 /*if (req->extraLen != 4*4 / *sizeof(char*) FIXME: assumes 64 bit addresses of .data and .bss are small enough * /) {
409 CmiPrintf("requested for a memory leak check with wrong information! %d bytes\n",req->extraLen);
411 /*if (sizeof(char*) == 4) {
412 / * 32 bit addresses; for 64 bit machines it assumes the following addresses were small enough * /
413 begin_data = (char*)ntohl(((int*)(req->extra))[0]);
414 end_data = (char*)ntohl(((int*)(req->extra))[1]) - sizeof(char*) + 1;
415 begin_bss = (char*)ntohl(((int*)(req->extra))[2]);
416 end_bss = (char*)ntohl(((int*)(req->extra))[3]) - sizeof(char*) + 1;
418 CmiAbort("not ready yet");
419 begin_data = ntohl(((char**)(req->extra))[0]);
420 end_data = ntohl(((char**)(req->extra))[1]) - sizeof(char*) + 1;
421 begin_bss = ntohl(((char**)(req->extra))[2]);
422 end_bss = ntohl(((char**)(req->extra))[3]) - sizeof(char*) + 1;
424 printf("scanning stack from %p to %p\n", (void *)begin_stack
, (void *)end_stack
);
425 for (scanner
= begin_stack
; scanner
< end_stack
; scanner
+=sizeof(char*)) {
426 fnd
= (Slot
**)CkHashtableGet(table
, scanner
);
427 //if (fnd != NULL) printf("scanning stack %p, %d\n",*fnd,isLeakSlot(*fnd));
428 if (fnd
!= NULL
&& isLeakSlot(*fnd
)) {
430 /* mark slot as not leak */
431 //printf("stack pointing to %p\n",found+1);
432 found
->magic
&= ~LEAK_FLAG
;
433 /* move the slot into inProgress */
434 PCQueuePush(inProgress
, (char*)found
);
437 printf("scanning data from %p to %p\n", (void *)info
->begin_data
, (void *)info
->end_data
);
438 for (scanner
= info
->begin_data
; scanner
< info
->end_data
; scanner
+=sizeof(char*)) {
439 //fprintf(fd, "scanner = %p\n",scanner);
441 fnd
= (Slot
**)CkHashtableGet(table
, scanner
);
442 //if (fnd != NULL) printf("scanning data %p, %d\n",*fnd,isLeakSlot(*fnd));
443 if (fnd
!= NULL
&& isLeakSlot(*fnd
)) {
445 /* mark slot as not leak */
446 //printf("data pointing to %p\n",found+1);
447 found
->magic
&= ~LEAK_FLAG
;
448 /* move the slot into inProgress */
449 PCQueuePush(inProgress
, (char*)found
);
452 printf("scanning bss from %p to %p\n", (void *)info
->begin_bss
, (void *)info
->end_bss
);
453 for (scanner
= info
->begin_bss
; scanner
< info
->end_bss
; scanner
+=sizeof(char*)) {
454 //printf("bss: %p %p\n",scanner,*(char**)scanner);
455 fnd
= (Slot
**)CkHashtableGet(table
, scanner
);
456 //if (fnd != NULL) printf("scanning bss %p, %d\n",*fnd,isLeakSlot(*fnd));
457 if (fnd
!= NULL
&& isLeakSlot(*fnd
)) {
459 /* mark slot as not leak */
460 //printf("bss pointing to %p\n",found+1);
461 found
->magic
&= ~LEAK_FLAG
;
462 /* move the slot into inProgress */
463 PCQueuePush(inProgress
, (char*)found
);
468 // continue iteratively to check the memory by sweeping it with the
470 while ((sl
= (Slot
*)PCQueuePop(inProgress
)) != NULL
) {
471 //printf("scanning memory %p of size %d\n",sl,sl->userSize);
472 /* scan through this memory and pick all the slots which are still leaking
473 and add them to the inProgress list */
474 if (sl
->extraStack
!= NULL
&& sl
->extraStack
->protectedMemory
!= NULL
) mprotect(sl
->extraStack
->protectedMemory
, sl
->extraStack
->protectedMemoryLength
, PROT_READ
);
475 for (scanner
= SlotToUser(sl
); scanner
< SlotToUser(sl
)+sl
->userSize
-sizeof(char*)+1; scanner
+=sizeof(char*)) {
476 fnd
= (Slot
**)CkHashtableGet(table
, scanner
);
477 //if (fnd != NULL) printf("scanning heap %p, %d\n",*fnd,isLeakSlot(*fnd));
478 if (fnd
!= NULL
&& isLeakSlot(*fnd
)) {
480 /* mark slot as not leak */
481 //printf("heap pointing to %p\n",found+1);
482 found
->magic
&= ~LEAK_FLAG
;
483 /* move the slot into inProgress */
484 PCQueuePush(inProgress
, (char*)found
);
487 if (sl
->extraStack
!= NULL
&& sl
->extraStack
->protectedMemory
!= NULL
) mprotect(sl
->extraStack
->protectedMemory
, sl
->extraStack
->protectedMemoryLength
, PROT_NONE
);
491 // move back all the entries in leaking to slot_first
492 /*if (leaking.next != &leaking) {
493 leaking.next->prev = slot_first;
494 leaking.prev->next = slot_first->next;
495 slot_first->next->prev = leaking.prev;
496 slot_first->next = leaking.next;
500 // mark all the entries in the leaking list as leak, and put them back
501 // into the main list
503 while (sl != &leaking) {
504 sl->magic | LEAK_FLAG;
506 if (leaking.next != &leaking) {
507 slot_first->next->prev = leaking.prev;
508 leaking.prev->next = slot_first->next;
509 leaking.next->prev = slot_first;
510 slot_first->next = leaking.next;
514 PCQueueDestroy(inProgress
);
515 CkDeleteHashtable(table
);
517 memory_charmdebug_internal
= 0;
521 void CpdMemoryMarkClean(char *msg
) {
523 /* The first byte of the data packet indicates if we want o mark or unmark */
524 if ((msg
+CmiMsgHeaderSizeBytes
)[0]) {
525 SLOT_ITERATE_START(sl
)
526 sl
->magic
|= LEAK_CLEAN
;
529 SLOT_ITERATE_START(sl
)
530 sl
->magic
&= ~LEAK_CLEAN
;
536 /****************** memory allocation tree ******************/
538 /* This allows the representation and creation of a tree where each node
539 * represents a line in the code part of a stack trace of a malloc. The node
540 * contains how much data has been allocated starting from that line of code,
544 typedef struct _AllocationPoint AllocationPoint
;
546 struct _AllocationPoint
{
547 /* The stack pointer this allocation refers to */
549 /* Pointer to the parent AllocationPoint of this AllocationPoint in the tree */
550 AllocationPoint
* parent
;
551 /* Pointer to the first child AllocationPoint in the tree */
552 AllocationPoint
* firstChild
;
553 /* Pointer to the sibling of this AllocationPoint (i.e the next child of the parent) */
554 AllocationPoint
* sibling
;
555 /* Pointer to the next AllocationPoint with the same key.
556 * There can be more than one AllocationPoint with the same key because the
557 * parent can be different. Used only in the hashtable. */
558 AllocationPoint
* next
;
559 /* Size of the memory allocate */
561 /* How many blocks have been allocated from this point */
563 /* Flags pertaining to the allocation point, currently only LEAK_FLAG */
567 // pup a single AllocationPoint. The data structure must be already allocated
568 void pupAllocationPointSingle(pup_er p
, AllocationPoint
*node
, int *numChildren
) {
569 AllocationPoint
*child
;
570 pup_pointer(p
, &node
->key
);
571 pup_int(p
, &node
->size
);
572 pup_int(p
, &node
->count
);
573 pup_char(p
, &node
->flags
);
574 if (pup_isUnpacking(p
)) {
576 node
->firstChild
= NULL
;
577 node
->sibling
= NULL
;
581 for (child
= node
->firstChild
; child
!= NULL
; child
= child
->sibling
) (*numChildren
) ++;
582 pup_int(p
, numChildren
);
586 // TODO: the following pup does not work for unpacking!
587 void pupAllocationPoint(pup_er p
, void *data
) {
588 AllocationPoint
*node
= (AllocationPoint
*)data
;
590 AllocationPoint
*child
;
591 pupAllocationPointSingle(p
, node
, &numChildren
);
592 for (child
= node
->firstChild
; child
!= NULL
; child
= child
->sibling
) {
593 pupAllocationPoint(p
, child
);
597 void deleteAllocationPoint(void *ptr
) {
598 AllocationPoint
*node
= (AllocationPoint
*)ptr
;
599 AllocationPoint
*child
;
600 for (child
= node
->firstChild
; child
!= NULL
; child
= child
->sibling
) deleteAllocationPoint(child
);
606 void printAllocationTree(AllocationPoint
*node
, FILE *fd
, int depth
) {
609 AllocationPoint
*child
;
611 if (node
==NULL
) return;
612 for (child
= node
->firstChild
; child
!= NULL
; child
= child
->sibling
) numChildren
++;
613 for (i
=0; i
<depth
; ++i
) fprintf(fd
, " ");
614 fprintf(fd
, "node %p: bytes=%d, count=%d, child=%d\n",(void *)node
->key
,node
->size
,node
->count
,numChildren
);
615 printAllocationTree(node
->sibling
, fd
, depth
);
616 printAllocationTree(node
->firstChild
, fd
, depth
+2);
619 AllocationPoint
* CreateAllocationTree(int *nodesCount
) {
623 AllocationPoint
*parent
, **start
, *cur
;
624 AllocationPoint
*root
= NULL
;
628 CkHashtableIterator_c it
;
629 AllocationPoint
**startscan
, *scan
;
631 table
= CkCreateHashtable_pointer(sizeof(char *), 10000);
634 root
= (AllocationPoint
*) mm_malloc(sizeof(AllocationPoint
));
636 *(AllocationPoint
**)CkHashtablePut(table
, &numNodes
) = root
;
643 root
->firstChild
= NULL
;
644 root
->sibling
= NULL
;
647 SLOT_ITERATE_START(scanner
)
649 for (i
=scanner
->stackLen
-1; i
>=0; --i
) {
651 start
= (AllocationPoint
**)CkHashtableGet(table
, &scanner
->from
[i
]);
654 cur
= (AllocationPoint
*) mm_malloc(sizeof(AllocationPoint
));
659 *(AllocationPoint
**)CkHashtablePut(table
, &scanner
->from
[i
]) = cur
;
661 for (cur
= (*start
)->next
; cur
!= *start
&& cur
->parent
!= parent
; cur
= cur
->next
);
662 if (cur
->parent
!= parent
) {
664 cur
= (AllocationPoint
*) mm_malloc(sizeof(AllocationPoint
));
668 cur
->next
= (*start
)->next
;
669 (*start
)->next
= cur
;
672 // here "cur" points to the correct AllocationPoint for this stack frame
674 cur
->key
= scanner
->from
[i
];
675 cur
->parent
= parent
;
679 cur
->firstChild
= NULL
;
680 //if (parent == NULL) {
681 // cur->sibling = NULL;
682 // CmiAssert(root == NULL);
685 cur
->sibling
= parent
->firstChild
;
686 parent
->firstChild
= cur
;
689 cur
->size
+= scanner
->userSize
;
691 cur
->flags
|= isLeakSlot(scanner
);
696 sprintf(filename
, "allocationTree_%d", CmiMyPe());
697 fd
= fopen(filename
, "w");
698 fprintf(fd
, "digraph %s {\n", filename
);
699 it
= CkHashtableGetIterator(table
);
700 while ((startscan
=(AllocationPoint
**)CkHashtableIteratorNext(it
,NULL
))!=NULL
) {
701 fprintf(fd
, "\t\"n%p\" [label=\"%p\\nsize=%d\\ncount=%d\"];\n",(void *)*startscan
,(void *)(*startscan
)->key
,
702 (*startscan
)->size
,(*startscan
)->count
);
703 for (scan
= (*startscan
)->next
; scan
!= *startscan
; scan
= scan
->next
) {
704 fprintf(fd
, "\t\"n%p\" [label=\"%p\\nsize=%d\\ncount=%d\"];\n",(void *)scan
,(void *)scan
->key
,scan
->size
,scan
->count
);
707 CkHashtableIteratorSeekStart(it
);
708 while ((startscan
=(AllocationPoint
**)CkHashtableIteratorNext(it
,NULL
))!=NULL
) {
709 fprintf(fd
, "\t\"n%p\" -> \"n%p\";\n",(void *)(*startscan
)->parent
,(void *)(*startscan
));
710 for (scan
= (*startscan
)->next
; scan
!= *startscan
; scan
= scan
->next
) {
711 fprintf(fd
, "\t\"n%p\" -> \"n%p\";\n",(void *)scan
->parent
,(void *)scan
);
717 sprintf(filename
, "allocationTree_%d.tree", CmiMyPe());
718 fd
= fopen(filename
, "w");
719 printAllocationTree(root
, fd
, 0);
722 CkDeleteHashtable(table
);
723 if (nodesCount
!= NULL
) *nodesCount
= numNodes
;
727 void MergeAllocationTreeSingle(AllocationPoint
*node
, AllocationPoint
*remote
, int numChildren
, pup_er p
) {
728 AllocationPoint child
;
729 int numChildChildren
;
731 //pupAllocationPointSingle(p, &remote, &numChildren);
732 /* Update the node with the information coming from remote */
733 node
->size
+= remote
->size
;
734 node
->count
+= remote
->count
;
735 node
->flags
|= remote
->flags
;
736 /* Recursively merge the children */
737 for (i
=0; i
<numChildren
; ++i
) {
738 AllocationPoint
*localChild
;
739 pupAllocationPointSingle(p
, &child
, &numChildChildren
);
740 /* Find the child in the local tree */
741 for (localChild
= node
->firstChild
; localChild
!= NULL
; localChild
= localChild
->sibling
) {
742 if (localChild
->key
== child
.key
) {
746 if (localChild
== NULL
) {
747 /* This child did not exist locally, allocate it */
749 localChild
= (AllocationPoint
*) mm_malloc(sizeof(AllocationPoint
));
751 localChild
->key
= child
.key
;
752 localChild
->flags
= 0;
753 localChild
->count
= 0;
754 localChild
->size
= 0;
755 localChild
->firstChild
= NULL
;
756 localChild
->next
= NULL
;
757 localChild
->parent
= node
;
758 localChild
->sibling
= node
->firstChild
;
759 node
->firstChild
= localChild
;
761 MergeAllocationTreeSingle(localChild
, &child
, numChildChildren
, p
);
765 void * MergeAllocationTree(int *size
, void *data
, void **remoteData
, int numRemote
) {
767 for (i
=0; i
<numRemote
; ++i
) {
768 pup_er p
= pup_new_fromMem(remoteData
[i
]);
769 AllocationPoint root
;
771 pupAllocationPointSingle(p
, &root
, &numChildren
);
772 MergeAllocationTreeSingle((AllocationPoint
*)data
, &root
, numChildren
, p
);
778 /********************** Memory statistics ***********************/
780 /* Collect the statistics relative to the amount of memory allocated.
781 * Starts from the statistics of a single processor and combines them to contain
782 * all the processors in the application.
785 typedef struct MemStatSingle
{
786 // [0] is total, [1] is the leaking part
792 typedef struct MemStat
{
794 MemStatSingle array
[1];
797 void pupMemStat(pup_er p
, void *st
) {
799 MemStat
*comb
= (MemStat
*)st
;
800 pup_fmt_sync_begin_object(p
);
801 pup_comment(p
, "count");
802 pup_int(p
, &comb
->count
);
803 pup_comment(p
, "list");
804 pup_fmt_sync_begin_array(p
);
805 for (i
=0; i
<comb
->count
; ++i
) {
806 MemStatSingle
*stat
= &comb
->array
[i
];
807 pup_fmt_sync_item(p
);
808 pup_comment(p
, "pe");
809 pup_int(p
, &stat
->pe
);
810 pup_comment(p
, "totalsize");
811 pup_ints(p
, stat
->sizes
[0], 5);
812 pup_comment(p
, "totalcount");
813 pup_ints(p
, stat
->counts
[0], 5);
814 pup_comment(p
, "leaksize");
815 pup_ints(p
, stat
->sizes
[1], 5);
816 pup_comment(p
, "leakcount");
817 pup_ints(p
, stat
->counts
[1], 5);
819 pup_fmt_sync_end_array(p
);
820 pup_fmt_sync_end_object(p
);
823 void deleteMemStat(void *ptr
) {
829 static int memStatReturnOnlyOne
= 1;
830 void * mergeMemStat(int *size
, void *data
, void **remoteData
, int numRemote
) {
832 if (memStatReturnOnlyOne
) {
833 MemStatSingle
*l
= &((MemStat
*) data
)->array
[0];
835 MemStatSingle
*m
= &r
.array
[0];
837 for (i
=0; i
<numRemote
; ++i
) {
838 pup_er p
= pup_new_fromMem(remoteData
[i
]);
840 for (j
=0; j
<2; ++j
) {
841 for (k
=0; k
<5; ++k
) {
842 l
->sizes
[j
][k
] += m
->sizes
[j
][k
];
843 l
->counts
[j
][k
] += m
->counts
[j
][k
];
850 MemStat
*l
= (MemStat
*)data
, *res
;
852 int count
= l
->count
;
853 for (i
=0; i
<numRemote
; ++i
) count
+= ((MemStat
*)remoteData
[i
])->count
;
855 res
= (MemStat
*)mm_malloc(sizeof(MemStat
) + (count
-1)*sizeof(MemStatSingle
));
857 memset(res
, 0, sizeof(MemStat
)+(count
-1)*sizeof(MemStatSingle
));
859 memcpy(res
->array
, l
->array
, l
->count
*sizeof(MemStatSingle
));
861 for (i
=0; i
<numRemote
; ++i
) {
862 pup_er p
= pup_new_fromMem(remoteData
[i
]);
864 memcpy(&res
->array
[count
], r
.array
, r
.count
*sizeof(MemStatSingle
));
873 MemStat
* CreateMemStat(void) {
878 st
= (MemStat
*)mm_calloc(1, sizeof(MemStat
));
881 stat
= &st
->array
[0];
882 SLOT_ITERATE_START(cur
)
883 stat
->sizes
[0][(cur
->magic
&0x7)] += cur
->userSize
;
884 stat
->counts
[0][(cur
->magic
&0x7)] ++;
885 if (cur
->magic
& 0x8) {
886 stat
->sizes
[1][(cur
->magic
&0x7)] += cur
->userSize
;
887 stat
->counts
[1][(cur
->magic
&0x7)] ++;
895 /*********************** Cross-chare corruption detection *******************/
896 static int reportMEM
= 0;
898 /* This first method uses two fields (userCRC and slotCRC) of the Slot structure
899 * to store the CRC32 checksum of the user data and the slot itself. It compares
900 * the stored values against a new value recomputed after the entry method
901 * returned to detect cross-chare corruption.
904 static int CpdCRC32
= 0;
906 #define SLOT_CRC_LENGTH (sizeof(Slot) - 2*sizeof(CmiUInt8))
908 static int checkSlotCRC(void *userPtr
) {
909 Slot
*sl
= UserToSlot(userPtr
);
911 unsigned int crc
= crc32_initial((unsigned char*)sl
, SLOT_CRC_LENGTH
);
912 crc
= crc32_update((unsigned char*)sl
->from
, sl
->stackLen
*sizeof(void*), crc
);
913 return sl
->slotCRC
== crc
;
917 static int checkUserCRC(void *userPtr
) {
918 Slot
*sl
= UserToSlot(userPtr
);
919 if (sl
!=NULL
) return sl
->userCRC
== crc32_initial((unsigned char*)userPtr
, sl
->userSize
);
923 static void resetUserCRC(void *userPtr
) {
924 Slot
*sl
= UserToSlot(userPtr
);
925 if (sl
!=NULL
) sl
->userCRC
= crc32_initial((unsigned char*)userPtr
, sl
->userSize
);
928 static void resetSlotCRC(void *userPtr
) {
929 Slot
*sl
= UserToSlot(userPtr
);
931 unsigned int crc
= crc32_initial((unsigned char*)sl
, SLOT_CRC_LENGTH
);
932 crc
= crc32_update((unsigned char*)sl
->from
, sl
->stackLen
*sizeof(void*), crc
);
937 static void ResetAllCRC(void) {
939 unsigned int crc1
, crc2
;
941 SLOT_ITERATE_START(cur
)
942 crc1
= crc32_initial((unsigned char*)cur
, SLOT_CRC_LENGTH
);
943 crc1
= crc32_update((unsigned char*)cur
->from
, cur
->stackLen
*sizeof(void*), crc1
);
944 crc2
= crc32_initial((unsigned char*)SlotToUser(cur
), cur
->userSize
);
950 static void CheckAllCRC(void) {
952 unsigned int crc1
, crc2
;
954 SLOT_ITERATE_START(cur
)
955 crc1
= crc32_initial((unsigned char*)cur
, SLOT_CRC_LENGTH
);
956 crc1
= crc32_update((unsigned char*)cur
->from
, cur
->stackLen
*sizeof(void*), crc1
);
957 crc2
= crc32_initial((unsigned char*)SlotToUser(cur
), cur
->userSize
);
958 /* Here we can check if a modification has occured */
959 if (reportMEM
&& cur
->slotCRC
!= crc1
) CmiPrintf("CRC: Object %d modified slot for %p\n",memory_chare_id
,(void *)SlotToUser(cur
));
961 if (reportMEM
&& cur
->userCRC
!= crc2
&& memory_chare_id
!= cur
->chareID
)
962 CmiPrintf("CRC: Object %d modified memory of object %d for %p\n",memory_chare_id
,cur
->chareID
,(void *)SlotToUser(cur
));
967 /* This second method requires all the memory in the processor to be copied
968 * into a safe region, and then compare it with the working copy after the
969 * entry method returned.
972 static int CpdMemBackup
= 0;
974 static void backupMemory(void) {
977 int totalMemory
= SLOTSPACE
;
978 if (*memoryBackup
!= NULL
)
979 CmiAbort("memoryBackup != NULL\n");
982 SLOT_ITERATE_START(cur
)
983 totalMemory
+= sizeof(Slot
) + cur
->userSize
+ cur
->stackLen
*sizeof(void*);
986 if (reportMEM
) CmiPrintf("CPD: total memory in use (%d): %d\n",CmiMyPe(),totalMemory
);
988 *memoryBackup
= (char *)mm_malloc(totalMemory
);
992 #ifndef CMK_SEPARATE_SLOT
993 memcpy(*memoryBackup
, slot_first
, sizeof(Slot
));
996 SLOT_ITERATE_START(cur
)
997 int tocopy
= SLOTSPACE
+ cur
->userSize
+ cur
->stackLen
*sizeof(void*);
998 char *data
= (char *)cur
;
999 #ifdef CMK_SEPARATE_SLOT
1000 memcpy(ptr
, cur
, sizeof(Slot
));
1001 ptr
+= sizeof(Slot
);
1002 data
= SlotToUser(cur
);
1004 memcpy(ptr
, data
, tocopy
);
1005 cur
->magic
&= ~ (NEW_BLOCK
| MODIFIED
);
1008 allocatedSinceSize
= 0;
1011 static void checkBackup(void) {
1012 #ifndef CMK_SEPARATE_SLOT
1013 Slot
*cur
= slot_first
->next
;
1014 char *ptr
= *memoryBackup
+ sizeof(Slot
);
1016 // skip over the new allocated blocks
1017 //while (cur != ((Slot*)*memoryBackup)->next) cur = cur->next;
1018 int idx
= allocatedSinceSize
-1;
1020 while (idx
>= 0 && allocatedSince
[idx
] != cur
) idx
--;
1027 while (cur
!= slot_first
) {
1029 // ptr is the old copy of cur
1030 if (memory_chare_id
!= cur
->chareID
) {
1031 int res
= memcmp(ptr
+sizeof(Slot
), ((char*)cur
)+sizeof(Slot
), cur
->userSize
+ cur
->stackLen
*sizeof(void*));
1033 cur
->magic
|= MODIFIED
;
1034 if (reportMEM
) CmiPrintf("CPD: Object %d modified memory of object %d for %p on pe %d\n",memory_chare_id
,cur
->chareID
,(void *)(cur
+1),CmiMyPe());
1038 // advance to next, skipping deleted memory blocks
1042 ptr
+= sizeof(Slot
) + ((Slot
*)ptr
)->userSize
+ ((Slot
*)ptr
)->stackLen
*sizeof(void*);
1043 } while (((Slot
*)last
)->next
!= cur
);
1048 mm_free(*memoryBackup
);
1050 *memoryBackup
= NULL
;
1053 /* Third method to detect cross-chare corruption. Use mprotect to change the
1054 * protection bits of each page, and a following segmentation fault to detect
1055 * the corruption. It is more accurate as it can provide the stack trace of the
1056 * first instruction that modified the memory.
1061 static int CpdMprotect
= 0;
1063 static void** unProtectedPages
= NULL
;
1064 static int unProtectedPagesSize
= 0;
1065 static int unProtectedPagesMaxSize
= 0;
1067 static void* lastAddressSegv
;
1068 static void CpdMMAPhandler(int sig
, siginfo_t
*si
, void *unused
){
1069 void *pageToUnprotect
;
1070 if (lastAddressSegv
== si
->si_addr
) {
1071 CmiPrintf("Second SIGSEGV at address 0x%lx\n", (long) si
->si_addr
);
1074 lastAddressSegv
= si
->si_addr
;
1075 pageToUnprotect
= (void*)(uintptr_t)((CmiUInt8
)(uintptr_t)si
->si_addr
& ~(CmiGetPageSize()-1));
1076 mprotect(pageToUnprotect
, 4, PROT_READ
|PROT_WRITE
);
1077 if (unProtectedPagesSize
>= unProtectedPagesMaxSize
) {
1078 void **newUnProtectedPages
;
1079 unProtectedPagesMaxSize
+= 10;
1081 newUnProtectedPages
= (void**)mm_malloc((unProtectedPagesMaxSize
)*sizeof(void*));
1082 memcpy(newUnProtectedPages
, unProtectedPages
, unProtectedPagesSize
*sizeof(void*));
1083 mm_free(unProtectedPages
);
1085 unProtectedPages
= newUnProtectedPages
;
1087 unProtectedPages
[unProtectedPagesSize
++] = pageToUnprotect
;
1088 if (reportMEM
) CpdNotify(CPD_CROSSCORRUPTION
, si
->si_addr
, memory_chare_id
);
1089 //CmiPrintf("Got SIGSEGV at address: 0x%lx\n", (long) si->si_addr);
1090 //CmiPrintStackTrace(0);
1093 static void protectMemory(void) {
1096 /*printf("protecting memory (chareid=%d)",memory_chare_id);*/
1097 SLOT_ITERATE_START(cur
)
1098 if (cur
->chareID
!= memory_chare_id
&& cur
->chareID
> 0) {
1099 /*printf(" %p",cur->userData);*/
1100 #ifdef CMK_SEPARATE_SLOT
1101 char * data
= cur
->userData
;
1103 char * data
= (char *)cur
;
1105 cur
->magic
|= BLOCK_PROTECTED
;
1106 mprotect(data
, cur
->userSize
+SLOTSPACE
+cur
->stackLen
*sizeof(void*), PROT_READ
);
1107 } /*else printf(" (%p)",cur->userData);*/
1113 static void unProtectMemory(void) {
1116 SLOT_ITERATE_START(cur
)
1117 #ifdef CMK_SEPARATE_SLOT
1118 char * data
= cur
->userData
;
1120 char * data
= (char *)cur
;
1122 mprotect(data
, cur
->userSize
+SLOTSPACE
+cur
->stackLen
*sizeof(void*), PROT_READ
|PROT_WRITE
);
1123 cur
->magic
&= ~BLOCK_PROTECTED
;
1125 /*printf("unprotecting memory\n");*/
1129 /** Called before the entry method: resets all current memory for the chare
1130 * receiving the message.
1132 void CpdResetMemory(void) {
1133 if (CpdMemBackup
) backupMemory();
1134 if (CpdCRC32
) ResetAllCRC();
1135 if (CpdMprotect
) protectMemory();
1138 /** Called after the entry method to check if the chare that just received the
1139 * message has corrupted the memory of some other chare, or some system memory.
1141 void CpdCheckMemory(void) {
1143 if (CpdMprotect
) unProtectMemory();
1144 if (CpdCRC32
) CheckAllCRC();
1145 if (CpdMemBackup
) checkBackup();
1146 SLOT_ITERATE_START(cur
)
1147 if (cur
->magic
== SLOTMAGIC_FREED
) CmiAbort("SLOT deallocate in list");
1148 if (cur
->from
== NULL
) printf("SLOT %p has no stack\n",(void *)cur
);
1149 #ifndef CMK_SEPARATE_SLOT
1150 if (cur
->next
== NULL
) printf("SLOT %p has null next!\n",(void *)cur
);
1155 void CpdSystemEnter(void) {
1158 if (++cpdInSystem
== 1) {
1161 SLOT_ITERATE_START(cur
)
1162 if (cur
->chareID
== 0) {
1163 #ifdef CMK_SEPARATE_SLOT
1164 char * data
= cur
->userData
;
1166 char * data
= (char *)cur
;
1168 mprotect(data
, cur
->userSize
+SLOTSPACE
+cur
->stackLen
*sizeof(void*), PROT_READ
|PROT_WRITE
);
1169 cur
->magic
&= ~BLOCK_PROTECTED
;
1173 //printf("CpdSystemEnter: unprotected %d elements\n",count);
1179 void CpdSystemExit(void) {
1183 if (--cpdInSystem
== 0) {
1186 SLOT_ITERATE_START(cur
)
1187 if (cur
->chareID
== 0) {
1188 #ifdef CMK_SEPARATE_SLOT
1189 char * data
= cur
->userData
;
1191 char * data
= (char *)cur
;
1193 cur
->magic
|= BLOCK_PROTECTED
;
1194 mprotect(data
, cur
->userSize
+SLOTSPACE
+cur
->stackLen
*sizeof(void*), PROT_READ
);
1198 //printf("CpdSystemExit: protected %d elements\n",count);
1199 /* unprotect the pages that have been unprotected by a signal SEGV */
1200 for (i
=0; i
<unProtectedPagesSize
; ++i
) {
1201 mprotect(unProtectedPages
[i
], 4, PROT_READ
|PROT_WRITE
);
1211 / *Head of the current circular allocated block list* /
1212 Slot slot_first_storage={&slot_first_storage,&slot_first_storage};
1213 Slot *slot_first=&slot_first_storage;
1215 #define CMI_MEMORY_ROUTINES 1
1217 / * Mark all allocated memory as being OK * /
1218 void CmiMemoryMark(void) {
1220 / * Just make a new linked list of slots * /
1221 slot_first=(Slot *)mm_malloc(sizeof(Slot));
1222 slot_first->next=slot_first->prev=slot_first;
1226 / * Mark this allocated block as being OK * /
1227 void CmiMemoryMarkBlock(void *blk) {
1228 Slot *s=Slot_fmUser(blk);
1230 if (s->magic!=SLOTMAGIC) CmiAbort("CmiMemoryMarkBlock called on non-malloc'd block!\n");
1231 / * Splice us out of the current linked list * /
1232 s->next->prev=s->prev;
1233 s->prev->next=s->next;
1234 s->prev=s->next=s; / * put us in our own list * /
1238 / * Print out all allocated memory * /
1239 void CmiMemorySweep(const char *where) {
1241 int nBlocks=0,nBytes=0;
1243 cur=slot_first->next;
1244 CmiPrintf("[%d] ------- LEAK CHECK: %s -----\n",CmiMyPe(), where);
1245 while (cur!=slot_first) {
1247 nBlocks++; nBytes+=cur->userSize;
1251 CmiPrintf("[%d] Total leaked memory: %d blocks, %d bytes\n",
1252 CmiMyPe(),nBlocks,nBytes);
1253 / * CmiAbort("Memory leaks detected!\n"); * /
1258 void CmiMemoryCheck(void) {}
1262 /********** Allocation/Free ***********/
1264 static int stackTraceDisabled
= 0;
1265 #define MAX_STACK_FRAMES 2048
1266 static int numStackFrames
; // the number of frames presetn in stackFrames - 4 (this number is trimmed at 0
1267 static void *stackFrames
[MAX_STACK_FRAMES
];
1269 static void dumpStackFrames(void) {
1270 numStackFrames
=MAX_STACK_FRAMES
;
1271 if (stackTraceDisabled
==0) {
1272 stackTraceDisabled
= 1;
1273 CmiBacktraceRecordHuge(stackFrames
,&numStackFrames
);
1274 stackTraceDisabled
= 0;
1276 if (numStackFrames
< 0) numStackFrames
= 0;
1279 stackFrames
[0] = (void*)0;
1283 /* Write a valid slot to this field */
1284 static void *setSlot(Slot
**sl
,int userSize
) {
1285 #ifdef CMK_SEPARATE_SLOT
1289 static int mallocFirstTime
= 1;
1290 if (mallocFirstTime
) {
1291 mallocFirstTime
= 0;
1292 memory_charmdebug_internal
= 1;
1293 block_slots
= CkCreateHashtable_pointer(sizeof(Slot
), 10000);
1294 memory_charmdebug_internal
= 0;
1298 memory_charmdebug_internal
= 1;
1299 s
= (Slot
*)CkHashtablePut(block_slots
, sl
);
1300 memory_charmdebug_internal
= 0;
1306 char *user
=(char*)(s
+1);
1308 /* Splice into the slot list just past the head (part 1) */
1309 s
->next
=slot_first
->next
;
1311 /* Handle correctly memory protection while changing neighbor blocks */
1313 mprotect(s
->next
, 4, PROT_READ
| PROT_WRITE
);
1314 mprotect(s
->prev
, 4, PROT_READ
| PROT_WRITE
);
1316 /* Splice into the slot list just past the head (part 2) */
1321 /* fix crc for previous and next block */
1322 resetSlotCRC(s
->next
+ 1);
1323 resetSlotCRC(s
->prev
+ 1);
1326 if (isProtected(s
->next
)) mprotect(s
->next
, 4, PROT_READ
);
1327 if (isProtected(s
->prev
)) mprotect(s
->prev
, 4, PROT_READ
);
1331 /* Set the last 4 bits of magic to classify the memory together with the magic */
1332 s
->magic
=SLOTMAGIC
+ NEW_BLOCK
+ (memory_status_info
>0? USER_TYPE
: SYSTEM_TYPE
);
1333 //if (memory_status_info>0) printf("user allocation\n");
1334 s
->chareID
= memory_chare_id
;
1335 s
->userSize
=userSize
;
1336 s
->extraStack
=(SlotStack
*)0;
1338 /* Set the stack frames */
1339 s
->stackLen
=numStackFrames
;
1340 s
->from
=(void**)(user
+userSize
);
1341 memcpy(s
->from
, &stackFrames
[4], numStackFrames
*sizeof(void*));
1344 unsigned int crc
= crc32_initial((unsigned char*)s
, SLOT_CRC_LENGTH
);
1345 s
->slotCRC
= crc32_update((unsigned char*)s
->from
, numStackFrames
*sizeof(void*), crc
);
1346 s
->userCRC
= crc32_initial((unsigned char*)user
, userSize
);
1348 if (saveAllocationHistory
) {
1349 if (allocatedSinceSize
>= allocatedSinceMaxSize
) {
1350 Slot
**newAllocatedSince
;
1351 allocatedSinceMaxSize
+= 10;
1353 newAllocatedSince
= (Slot
**)mm_malloc((allocatedSinceMaxSize
)*sizeof(Slot
*));
1354 memcpy(newAllocatedSince
, allocatedSince
, allocatedSinceSize
*sizeof(Slot
*));
1355 mm_free(allocatedSince
);
1357 allocatedSince
= newAllocatedSince
;
1359 allocatedSince
[allocatedSinceSize
++] = s
;
1361 lastMemoryAllocated
= user
;
1363 return (void *)user
;
1366 /* Delete this slot structure */
1367 static void freeSlot(Slot
*s
) {
1368 #ifdef CMK_SEPARATE_SLOT
1369 /* Don't delete it from the hash table, simply mark it as freed */
1370 int removed
= CkHashtableRemove(block_slots
, &s
->userData
);
1372 /* WARNING! After the slot has been removed from the hashtable,
1373 * the pointer "s" becomes invalid.
1376 /* Handle correctly memory protection while changing neighbor blocks */
1378 mprotect(s
->next
, 4, PROT_READ
| PROT_WRITE
);
1379 mprotect(s
->prev
, 4, PROT_READ
| PROT_WRITE
);
1381 /* Splice out of the slot list */
1382 s
->next
->prev
=s
->prev
;
1383 s
->prev
->next
=s
->next
;
1385 /* fix crc for previous and next block */
1386 resetSlotCRC(s
->next
+ 1);
1387 resetSlotCRC(s
->prev
+ 1);
1390 if (isProtected(s
->next
)) mprotect(s
->next
, 4, PROT_READ
);
1391 if (isProtected(s
->prev
)) mprotect(s
->prev
, 4, PROT_READ
);
1393 s
->prev
=s
->next
=(Slot
*)0;//0x0F00; why was it not 0?
1395 s
->magic
=SLOTMAGIC_FREED
;
1400 /********** meta_ routines ***********/
1402 /* Only display startup status messages from processor 0 */
1403 static void status(const char *msg
) {
1404 if (CmiMyPe()==0 && !CmiArgGivingUsage()) {
1405 CmiPrintf("%s",msg
);
1409 extern int getCharmEnvelopeSize(void);
1411 static int disableVerbosity
= 1;
1412 int cpdInitializeMemory
;
1413 void CpdSetInitializeMemory(int v
) { cpdInitializeMemory
= v
; }
1415 static void meta_init(char **argv
) {
1416 if (CmiMyRank()==0) {
1418 status("Converse -memory mode: charmdebug\n");
1419 sprintf(buf
, "slot size %d\n", (int)sizeof(Slot
));
1421 CmiMemoryIs_flag
|=CMI_MEMORY_IS_CHARMDEBUG
;
1422 cpdInitializeMemory
= 0;
1423 charmEnvelopeSize
= getCharmEnvelopeSize();
1424 CpdDebugGetAllocationTree
= (void* (*)(int*))CreateAllocationTree
;
1425 CpdDebug_pupAllocationPoint
= pupAllocationPoint
;
1426 CpdDebug_deleteAllocationPoint
= deleteAllocationPoint
;
1427 CpdDebug_MergeAllocationTree
= MergeAllocationTree
;
1428 CpdDebugGetMemStat
= (void* (*)(void))CreateMemStat
;
1429 CpdDebug_pupMemStat
= pupMemStat
;
1430 CpdDebug_deleteMemStat
= deleteMemStat
;
1431 CpdDebug_mergeMemStat
= mergeMemStat
;
1432 memory_allocated_user_total
= 0;
1434 #ifndef CMK_SEPARATE_SLOT
1435 slot_first
->userSize
= 0;
1436 slot_first
->stackLen
= 0;
1439 if (CmiGetArgFlagDesc(argv
,"+memory_report", "Print all cross-object violations")) {
1440 if (CmiMyRank()==0) reportMEM
= 1;
1442 if (CmiGetArgFlagDesc(argv
,"+memory_backup", "Backup all memory at every entry method")) {
1443 if (CmiMyRank()==0) {
1445 saveAllocationHistory
= 1;
1448 if (CmiGetArgFlagDesc(argv
,"+memory_crc", "Use CRC32 to detect memory changes")) {
1449 if (CmiMyRank()==0) CpdCRC32
= 1;
1452 if (CmiGetArgFlagDesc(argv
,"+memory_mprotect", "Use mprotect to protect memory of other chares")) {
1453 if (CmiMyRank()==0) {
1454 struct sigaction sa
;
1456 sa
.sa_flags
= SA_SIGINFO
| SA_NODEFER
| SA_RESTART
;
1457 sigemptyset(&sa
.sa_mask
);
1458 sa
.sa_sigaction
= CpdMMAPhandler
;
1459 if (sigaction(SIGSEGV
, &sa
, NULL
) == -1) CmiPrintf("failed to install signal handler\n");
1463 if (CmiGetArgFlagDesc(argv
,"+memory_verbose", "Print all memory-related operations")) {
1464 if (CmiMyRank()==0) disableVerbosity
= 0;
1466 if (CmiGetArgFlagDesc(argv
,"+memory_nostack", "Do not collect stack traces for memory allocations")) {
1467 if (CmiMyRank()==0) stackTraceDisabled
= 1;
1471 static void *meta_malloc(size_t size
) {
1473 if (memory_charmdebug_internal
==0) {
1478 s
=(Slot
*)mmap(NULL
, SLOTSPACE
+size
+numStackFrames
*sizeof(void*), PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
1480 s
=(Slot
*)mm_malloc(SLOTSPACE
+size
+numStackFrames
*sizeof(void*));
1484 user
= (char*)setSlot(&s
,size
);
1485 memory_allocated_user_total
+= size
;
1486 #if ! CMK_BIGSIM_CHARM
1487 traceMalloc_c(user
, size
, s
->from
, s
->stackLen
);
1490 if (disableVerbosity
== 0) {
1491 disableVerbosity
= 1;
1492 CmiPrintf("allocating %p: %d bytes\n",(void *)s
,size
);
1493 disableVerbosity
= 0;
1497 user
= mm_malloc(size
);
1500 if (cpdInitializeMemory
) {
1501 memset(user
, 0, size
); // for Record-Replay must initialize all memory otherwise paddings may differ (screwing up the CRC)
1506 static void meta_free(void *mem
) {
1507 if (memory_charmdebug_internal
==0) {
1510 if (mem
==NULL
) return; /*Legal, but misleading*/
1512 #if CMK_MEMORY_BUILD_OS
1513 /* In this situation, we can have frees that were not allocated by our malloc...
1514 * for now simply skip over them. */
1515 if (s
== NULL
|| ((s
->magic
&~FLAGS_MASK
) != SLOTMAGIC_VALLOC
&&
1516 (s
->magic
&~FLAGS_MASK
) != SLOTMAGIC
)) {
1524 /* Check that the memory is really allocated, and we can use its slot */
1528 ((s
->magic
&~FLAGS_MASK
) != SLOTMAGIC
&&
1529 (s
->magic
&~FLAGS_MASK
) != SLOTMAGIC_FREED
&&
1530 (s
->magic
&~FLAGS_MASK
) != SLOTMAGIC_VALLOC
)) {
1531 CmiAbort("Free'd non-malloc'd block");
1533 #ifdef CMK_SEPARATE_SLOT
1534 CmiAssert(s
->userData
== mem
);
1538 if (mem
!=NULL
) memSize
= s
->userSize
;
1539 memory_allocated_user_total
-= memSize
;
1540 #if ! CMK_BIGSIM_CHARM
1541 traceFree_c(mem
, memSize
);
1544 if (disableVerbosity
== 0) {
1545 disableVerbosity
= 1;
1546 CmiPrintf("freeing %p\n",(void *)mem
);
1547 disableVerbosity
= 0;
1550 /*Overwrite stack trace with the one of the free*/
1552 if (s
->stackLen
> numStackFrames
) s
->stackLen
=numStackFrames
;
1553 memcpy(s
->from
, &stackFrames
[4], s
->stackLen
*sizeof(void*));
1555 if ((s
->magic
&~FLAGS_MASK
)==SLOTMAGIC_VALLOC
)
1556 { /*Allocated with special alignment*/
1557 void *ptr
= s
->extraStack
;
1561 /*mm_free(((char *)mem)-CmiGetPageSize());*/
1564 else if ((s
->magic
&~FLAGS_MASK
)==SLOTMAGIC
)
1565 { /*Ordinary allocated block */
1566 int freeSize
=SLOTSPACE
+s
->userSize
+s
->stackLen
*sizeof(void*);
1569 #ifdef CMK_SEPARATE_SLOT
1576 munmap(ptr
, freeSize
);
1582 else if (s
->magic
==SLOTMAGIC_FREED
)
1583 CmiAbort("Free'd block twice");
1584 else /*Unknown magic number*/
1585 CmiAbort("Free'd non-malloc'd block");
1593 static void *meta_calloc(size_t nelem
, size_t size
) {
1594 void *area
=meta_malloc(nelem
*size
);
1595 if (area
!= NULL
) memset(area
,0,nelem
*size
);
1599 static void meta_cfree(void *mem
) {
1603 static void *meta_realloc(void *oldBuffer
, size_t newSize
) {
1604 void *newBuffer
= meta_malloc(newSize
);
1605 if ( newBuffer
&& oldBuffer
) {
1606 /*Preserve old buffer contents*/
1607 Slot
*o
=UserToSlot(oldBuffer
);
1608 size_t size
=o
->userSize
;
1609 if (size
>newSize
) size
=newSize
;
1611 memcpy(newBuffer
, oldBuffer
, size
);
1613 meta_free(oldBuffer
);
1618 static void *meta_memalign(size_t align
, size_t size
) {
1619 int overhead
= align
;
1624 while (overhead
< SLOTSPACE
+sizeof(SlotStack
)) overhead
+= align
;
1625 /* Allocate the required size + the overhead needed to keep the user alignment */
1629 alloc
=(char *)mm_memalign(align
,overhead
+size
+numStackFrames
*sizeof(void*));
1631 s
=(Slot
*)(alloc
+overhead
-SLOTSPACE
);
1632 user
=setSlot(&s
,size
);
1633 s
->magic
= SLOTMAGIC_VALLOC
+ (s
->magic
&0xF);
1634 s
->extraStack
= (SlotStack
*)alloc
; /* use the extra space as stack */
1635 s
->extraStack
->protectedMemory
= NULL
;
1636 s
->extraStack
->protectedMemoryLength
= 0;
1637 memory_allocated_user_total
+= size
;
1638 #if ! CMK_BIGSIM_CHARM
1639 traceMalloc_c(user
, size
, s
->from
, s
->stackLen
);
1644 static int meta_posix_memalign(void **outptr
, size_t align
, size_t size
) {
1645 int overhead
= align
;
1651 while (overhead
< SLOTSPACE
+sizeof(SlotStack
)) overhead
+= align
;
1652 /* Allocate the required size + the overhead needed to keep the user alignment */
1656 ret
= mm_posix_memalign(outptr
,align
,overhead
+size
+numStackFrames
*sizeof(void*));
1657 alloc
=(char *)*outptr
;
1661 s
=(Slot
*)(alloc
+overhead
-SLOTSPACE
);
1662 user
=setSlot(&s
,size
);
1663 s
->magic
= SLOTMAGIC_VALLOC
+ (s
->magic
&0xF);
1664 s
->extraStack
= (SlotStack
*)alloc
; /* use the extra space as stack */
1665 s
->extraStack
->protectedMemory
= NULL
;
1666 s
->extraStack
->protectedMemoryLength
= 0;
1667 memory_allocated_user_total
+= size
;
1668 #if ! CMK_BIGSIM_CHARM
1669 traceMalloc_c(user
, size
, s
->from
, s
->stackLen
);
1675 static void *meta_aligned_alloc(size_t align
, size_t size
) {
1676 int overhead
= align
;
1681 while (overhead
< SLOTSPACE
+sizeof(SlotStack
)) overhead
+= align
;
1682 /* Allocate the required size + the overhead needed to keep the user alignment */
1686 alloc
=(char *)mm_aligned_alloc(align
,overhead
+size
+numStackFrames
*sizeof(void*));
1688 s
=(Slot
*)(alloc
+overhead
-SLOTSPACE
);
1689 user
=setSlot(&s
,size
);
1690 s
->magic
= SLOTMAGIC_VALLOC
+ (s
->magic
&0xF);
1691 s
->extraStack
= (SlotStack
*)alloc
; /* use the extra space as stack */
1692 s
->extraStack
->protectedMemory
= NULL
;
1693 s
->extraStack
->protectedMemoryLength
= 0;
1694 memory_allocated_user_total
+= size
;
1695 #if ! CMK_BIGSIM_CHARM
1696 traceMalloc_c(user
, size
, s
->from
, s
->stackLen
);
1701 static void *meta_valloc(size_t size
) {
1702 return meta_memalign(CmiGetPageSize(),size
);
1705 static void *meta_pvalloc(size_t size
) {
1706 const size_t pagesize
= CmiGetPageSize();
1707 return meta_memalign(pagesize
, (size
+ pagesize
- 1) & ~(pagesize
- 1));
1710 void setProtection(char* mem
, char *ptr
, int len
, int flag
) {
1711 Slot
*sl
= UserToSlot(mem
);
1712 if (sl
->extraStack
== NULL
) CmiAbort("Tried to protect memory not memaligned\n");
1714 sl
->extraStack
->protectedMemory
= ptr
;
1715 sl
->extraStack
->protectedMemoryLength
= len
;
1717 sl
->extraStack
->protectedMemory
= NULL
;
1718 sl
->extraStack
->protectedMemoryLength
= 0;
1722 void **chareObjectMemory
= NULL
;
1723 int chareObjectMemorySize
= 0;
1725 void setMemoryTypeChare(void *ptr
) {
1726 Slot
*sl
= UserToSlot(ptr
);
1727 sl
->magic
= (sl
->magic
& ~FLAGS_MASK
) | CHARE_TYPE
;
1728 sl
->chareID
= nextChareID
;
1729 if (nextChareID
>= chareObjectMemorySize
) {
1732 newChare
= (void**)mm_malloc((nextChareID
+100) * sizeof(void*));
1734 memcpy(newChare
, chareObjectMemory
, chareObjectMemorySize
*sizeof(void*));
1735 chareObjectMemorySize
= nextChareID
+100;
1737 mm_free(chareObjectMemory
);
1739 chareObjectMemory
= newChare
;
1741 chareObjectMemory
[nextChareID
] = ptr
;
1745 /* The input parameter is the pointer to the envelope, after the CmiChunkHeader */
1746 void setMemoryTypeMessage(void *ptr
) {
1747 void *realptr
= (char*)ptr
- sizeof(CmiChunkHeader
);
1748 Slot
*sl
= UserToSlot(realptr
);
1749 if ((sl
->magic
&~FLAGS_MASK
) == SLOTMAGIC
|| (sl
->magic
&~FLAGS_MASK
) == SLOTMAGIC_VALLOC
) {
1750 sl
->magic
= (sl
->magic
& ~FLAGS_MASK
) | MESSAGE_TYPE
;
1754 int setMemoryChareIDFromPtr(void *ptr
) {
1755 int tmp
= memory_chare_id
;
1756 if (ptr
== NULL
|| ptr
== 0) memory_chare_id
= 0;
1757 else memory_chare_id
= UserToSlot(ptr
)->chareID
;
1761 void setMemoryChareID(int chareID
) {
1762 memory_chare_id
= chareID
;
1765 void setMemoryOwnedBy(void *ptr
, int chareID
) {
1766 Slot
*sl
= UserToSlot(ptr
);
1767 sl
->chareID
= chareID
;
1771 void * MemoryToSlot(void *ptr
) {
1774 #if defined(CPD_USE_MMAP) && defined(CMK_SEPARATE_SLOT)
1775 for (i
=0; i
<1000; ++i
) {
1776 sl
= UserToSlot((void*)(intptr_t)(((CmiUInt8
)(intptr_t)ptr
)-i
*CmiGetPageSize() & ~(CmiGetPageSize()-1)));
1777 if (sl
!= NULL
) return sl
;
1783 /*void PrintDebugStackTrace(void *ptr) {
1785 Slot *sl = UserToSlot((void*)(((CmiUInt8)ptr) & ~(CmiGetPageSize()-1)));
1787 CmiPrintf("%d %d ",sl->chareID,sl->stackLen);
1788 for (i=0; i<sl->stackLen; ++i) CmiPrintf("%p ",sl->from[i]);
1790 CmiPrintf("%d 0 ",sl->chareID);