ebff898bc3477ab4edbdb20eb00c578222e42ea1
[charm.git] / src / conv-core / memory-charmdebug.c
1 /*
2  * Filippo's charm debug memory module, gioachin@uiuc.edu, 2005/10
3  * based on Orion's memory-leak.c
4  *
5  * This special version of malloc() and company is meant to be used in
6  * conjunction with the parallel debugger CharmDebug.
7  *
8  * Functionalities provided:
9  * - detect multiple delete on a pointer
10  * - stacktrace for all memory allocated
11  * - division of the memory in differnt types of allocations
12  * - sweep of the memory searching for leaks
13  */
14
15 /* Use Gnumalloc as meta-meta malloc fallbacks (mm_*) */
16 #include "memory-gnu.c"
17 #include "tracec.h"
18
19 /* Utilities needed by the code */
20 #include "ckhashtable.h"
21
22 /*#include "pup_c.h" */
23
24 typedef struct _Slot Slot;
25 typedef struct _SlotStack SlotStack;
26
27 /**
28  * Struct Slot contains all of the information about a malloc buffer except
29  * for the contents of its memory.
30  */
31 struct _Slot {
32   /*Doubly-linked allocated block list*/
33   Slot *next;
34   Slot *prev;
35         
36   /*The number of bytes of user data*/
37   int userSize;
38
39 #define FLAGS_MASK        0xF
40 #define LEAK_FLAG         0x8
41 #define UNKNOWN_TYPE      0x0
42 #define SYSTEM_TYPE       0x1
43 #define USER_TYPE         0x2
44 #define CHARE_TYPE        0x3
45 #define MESSAGE_TYPE      0x4
46   /* A magic number field, to verify this is an actual malloc'd buffer, and what
47      type of allocation it is. The last 4 bits of the magic number are used to
48      define a classification of mallocs. */
49 #define SLOTMAGIC            0x8402a5e0
50 #define SLOTMAGIC_VALLOC     0x7402a5e0
51 #define SLOTMAGIC_FREED      0xDEADBEEF
52   int magic;
53
54   int pad;
55   /* Controls the number of stack frames to print out. Should be always odd, so
56      the total size of this struct becomes multiple of 8 bytes everywhere */
57 //#define STACK_LEN 15
58   int stackLen;
59   void **from;
60
61   /* Pointer to extra stacktrace, when the user requested more trace */
62   SlotStack *extraStack;
63 };
64
65 struct _SlotStack {
66   char *protectedMemory;
67   int protectedMemoryLength;
68   /* empty for the moment, to be filled when needed */
69 };
70
71 /*Convert a slot to a user address*/
72 static char *SlotToUser(Slot *s) {
73   return ((char *)s)+sizeof(Slot);
74 }
75
76
77 /*Convert a user address to a slot*/
78 static Slot *UserToSlot(void *user) {
79   char *cu=(char *)user;
80   Slot *s=(Slot *)(cu-sizeof(Slot));
81   return s;
82 }
83
84 static int isLeakSlot(Slot *s) {
85   return s->magic & LEAK_FLAG;
86 }
87
88 static void printSlot(Slot *s) {
89   CmiPrintf("[%d] Leaked block of %d bytes at %p:\n",
90             CmiMyPe(), s->userSize, SlotToUser(s));
91   CmiBacktracePrint(s->from,s->stackLen);
92 }
93
94 /********* Circural list of allocated memory *********/
95
96 /* First memory slot */
97 Slot slot_first_storage = {&slot_first_storage, &slot_first_storage};
98 Slot *slot_first = &slot_first_storage;
99
100 /********* Cpd routines for pupping data to the debugger *********/
101
102 int cpd_memory_length(void *lenParam) {
103   int n=0;
104   Slot *cur = slot_first->next;
105   while (cur != slot_first) {
106     n++;
107     cur = cur->next;
108   }
109   return n;
110 }
111
112 void cpd_memory_single_pup(Slot* list, pup_er p) {
113   Slot *cur = list->next;
114   /* Stupid hack to avoid sending the memory we just allocated for this packing,
115      otherwise the lenghts will mismatch */
116   if (pup_isPacking(p)) cur = cur->next;
117   while (cur != list) {
118     int i;
119     int flags;
120     void *loc = (void*)(cur+1);
121     CpdListBeginItem(p, 0);
122     pup_comment(p, "loc");
123     pup_pointer(p, &loc);
124     pup_comment(p, "size");
125     pup_int(p, &cur->userSize);
126     pup_comment(p, "flags");
127     flags = cur->magic & FLAGS_MASK;
128     pup_int(p, &flags);
129     pup_comment(p, "stack");
130     //for (i=0; i<STACK_LEN; ++i) {
131     //  if (cur->from[i] <= 0) break;
132       //      if (cur->from[i] > 0) pup_uint(p, (unsigned int*)&cur->from[i]);
133       //      else break;
134     //}
135     pup_pointers(p, cur->from, cur->stackLen);
136     cur = cur->next;
137   }
138 }
139
140 void cpd_memory_pup(void *itemParam, pup_er p, CpdListItemsRequest *req) {
141   CpdListBeginItem(p, 0);
142   pup_comment(p, "name");
143   pup_chars(p, "memory", strlen("memory"));
144   pup_comment(p, "slots");
145   pup_syncComment(p, pup_sync_begin_array, 0);
146   cpd_memory_single_pup(slot_first, p);
147   pup_syncComment(p, pup_sync_end_array, 0);
148 }
149
150 void check_memory_leaks(CpdListItemsRequest *);
151 void cpd_memory_leak(void *iterParam, pup_er p, CpdListItemsRequest *req) {
152   if (pup_isSizing(p)) {
153     // let's perform the memory leak checking. This is the first step in the
154     // packing, where we size, in the second step we pack and we avoid doing
155     // this check again.
156     check_memory_leaks(req);
157   }
158   cpd_memory_pup(iterParam, p, req);
159 }
160
161 int cpd_memory_getLength(void *lenParam) { return 1; }
162 void cpd_memory_get(void *iterParam, pup_er p, CpdListItemsRequest *req) {
163   void *userData = (void*)(((unsigned int)req->lo) + (((unsigned long)req->hi)<<32));
164   Slot *sl = ((Slot*)userData)-1;
165   CpdListBeginItem(p, 0);
166   pup_comment(p, "size");
167   //printf("value: %x %x %x %d\n",sl->magic, sl->magic&~FLAGS_MASK, SLOTMAGIC, ((sl->magic&~FLAGS_MASK) != SLOTMAGIC));
168   if ((sl->magic&~FLAGS_MASK) != SLOTMAGIC) {
169     int zero = 0;
170     pup_int(p, &zero);
171   } else {
172     pup_int(p, &sl->userSize);
173     pup_comment(p, "value");
174     pup_bytes(p, userData, sl->userSize);
175   }
176 }
177
178 /********* Heap Checking ***********/
179
180 int charmEnvelopeSize = 0;
181
182 // FIXME: this function assumes that all memory is allocated in slot_unknown!
183 void check_memory_leaks(CpdListItemsRequest *req) {
184   FILE* fd=fopen("check_memory_leaks", "w");
185   // Step 1)
186   // index all memory into a CkHashtable, with a scan of 4 bytes.
187   CkHashtable_c table;
188   Slot leaking, inProgress;
189   Slot *sl, **fnd, *found;
190   char *scanner;
191   char *begin_stack, *end_stack;
192   char *begin_data, *end_data;
193   char *begin_bss, *end_bss;
194   int growing_dimension = 0;
195
196   // copy all the memory from "slot_first" to "leaking"
197   slot_first->next->prev = &leaking;
198   slot_first->prev->next = &leaking;
199   leaking.prev = slot_first->prev;
200   leaking.next = slot_first->next;
201   slot_first->next = slot_first;
202   slot_first->prev = slot_first;
203
204   table = CkCreateHashtable_pointer(sizeof(char *), 10000);
205   for (sl = leaking.next; sl != &leaking; sl = sl->next) {
206     // index the i-th memory slot
207     char *ptr;
208     sl->magic |= LEAK_FLAG;
209     if (req->lo > 0) {
210       //CmiPrintf("checking memory fast\n");
211       // means index only specific offsets of the memory region
212       ptr = ((char*)sl)+sizeof(Slot);
213       char **object = (char**)CkHashtablePut(table, &ptr);
214       *object = (char*)sl;
215       ptr += 4;
216       object = (char**)CkHashtablePut(table, &ptr);
217       *object = (char*)sl;
218       // beginning of converse header
219       ptr += sizeof(CmiChunkHeader) - 4;
220       if (ptr < ((char*)sl)+2*sizeof(Slot)+sl->userSize) {
221         object = (char**)CkHashtablePut(table, &ptr);
222         *object = (char*)sl;
223       }
224       // beginning of charm header
225       ptr += CmiReservedHeaderSize;
226       if (ptr < ((char*)sl)+2*sizeof(Slot)+sl->userSize) {
227         object = (char**)CkHashtablePut(table, &ptr);
228         *object = (char*)sl;
229       }
230       // beginning of ampi header
231       ptr += charmEnvelopeSize - CmiReservedHeaderSize;
232       if (ptr < ((char*)sl)+2*sizeof(Slot)+sl->userSize) {
233         object = (char**)CkHashtablePut(table, &ptr);
234         *object = (char*)sl;
235       }
236     } else {
237       //CmiPrintf("checking memory extensively\n");
238       // means index every fourth byte of the memory region
239       for (ptr = ((char*)sl)+sizeof(Slot); ptr < ((char*)sl)+sizeof(Slot)+sl->userSize; ptr+=sizeof(char*)) {
240         //printf("memory %p\n",ptr);
241         //growing_dimension++;
242         //if ((growing_dimension&0xFF) == 0) printf("inserted %d objects\n",growing_dimension);
243         char **object = (char**)CkHashtablePut(table, &ptr);
244         *object = (char*)sl;
245       }
246     }
247   }
248
249   // Step 2)
250   // start the check with the stack and the global data. The stack is found
251   // through the current pointer, going up until 16 bits filling (considering
252   // the stack grows toward decreasing addresses). The pointers to the global
253   // data (segments .data and .bss) are passed in with "req" as the "extra"
254   // field, with the structure "begin .data", "end .data", "begin .bss", "end .bss".
255   inProgress.prev = &inProgress;
256   inProgress.next = &inProgress;
257   begin_stack = (char*)&table;
258   end_stack = memory_stack_top;
259   if (req->extraLen != 4*4/*sizeof(char*) FIXME: assumes 64 bit addresses of .data and .bss are small enough*/) {
260     CmiPrintf("requested for a memory leak check with wrong information! %d bytes\n",req->extraLen);
261   }
262   //if (sizeof(char*) == 4) {
263     /* 32 bit addresses; for 64 bit machines it assumes the following addresses were small enough */
264     begin_data = (char*)ntohl(((int*)(req->extra))[0]);
265     end_data = (char*)ntohl(((int*)(req->extra))[1]) - sizeof(char*) + 1;
266     begin_bss = (char*)ntohl(((int*)(req->extra))[2]);
267     end_bss = (char*)ntohl(((int*)(req->extra))[3]) - sizeof(char*) + 1;
268   /*} else {
269     CmiAbort("not ready yet");
270     begin_data = ntohl(((char**)(req->extra))[0]);
271     end_data = ntohl(((char**)(req->extra))[1]) - sizeof(char*) + 1;
272     begin_bss = ntohl(((char**)(req->extra))[2]);
273     end_bss = ntohl(((char**)(req->extra))[3]) - sizeof(char*) + 1;
274   }*/
275   printf("scanning stack from %p (%d) to %p (%d)\n",begin_stack,begin_stack,end_stack,end_stack);
276   for (scanner = begin_stack; scanner < end_stack; scanner+=sizeof(char*)) {
277     fnd = (Slot**)CkHashtableGet(table, scanner);
278     //if (fnd != NULL) printf("scanning stack %p, %d\n",*fnd,isLeakSlot(*fnd));
279     if (fnd != NULL && isLeakSlot(*fnd)) {
280       found = *fnd;
281       /* mark slot as not leak */
282       //printf("stack pointing to %p\n",found+1);
283       found->magic &= ~LEAK_FLAG;
284       /* move the slot a inProgress */
285       found->next->prev = found->prev;
286       found->prev->next = found->next;
287       found->next = inProgress.next;
288       found->prev = &inProgress;
289       found->next->prev = found;
290       found->prev->next = found;
291     }
292   }
293   printf("scanning data from %p (%d) to %p (%d)\n",begin_data,begin_data,end_data,end_data);
294   for (scanner = begin_data; scanner < end_data; scanner+=sizeof(char*)) {
295     //fprintf(fd, "scanner = %p\n",scanner);
296     fflush(fd);
297     fnd = (Slot**)CkHashtableGet(table, scanner);
298     //if (fnd != NULL) printf("scanning data %p, %d\n",*fnd,isLeakSlot(*fnd));
299     if (fnd != NULL && isLeakSlot(*fnd)) {
300       found = *fnd;
301       /* mark slot as not leak */
302       //printf("data pointing to %p\n",found+1);
303       found->magic &= ~LEAK_FLAG;
304       /* move the slot a inProgress */
305       found->next->prev = found->prev;
306       found->prev->next = found->next;
307       found->next = inProgress.next;
308       found->prev = &inProgress;
309       found->next->prev = found;
310       found->prev->next = found;
311     }
312   }
313   printf("scanning bss from %p (%d) to %p (%d)\n",begin_bss,begin_bss,end_bss,end_bss);
314   for (scanner = begin_bss; scanner < end_bss; scanner+=sizeof(char*)) {
315     //printf("bss: %p %p\n",scanner,*(char**)scanner);
316     fnd = (Slot**)CkHashtableGet(table, scanner);
317     //if (fnd != NULL) printf("scanning bss %p, %d\n",*fnd,isLeakSlot(*fnd));
318     if (fnd != NULL && isLeakSlot(*fnd)) {
319       found = *fnd;
320       /* mark slot as not leak */
321       //printf("bss pointing to %p\n",found+1);
322       found->magic &= ~LEAK_FLAG;
323       /* move the slot a inProgress */
324       found->next->prev = found->prev;
325       found->prev->next = found->next;
326       found->next = inProgress.next;
327       found->prev = &inProgress;
328       found->next->prev = found;
329       found->prev->next = found;
330     }
331   }
332
333   // Step 3)
334   // continue iteratively to check the memory by sweeping it with the
335   // "inProcess" list
336   while (inProgress.next != &inProgress) {
337     sl = inProgress.next;
338     printf("scanning memory %p of size %d\n",sl,sl->userSize);
339     /* move slot back to the main list (slot_first) */
340     sl->next->prev = sl->prev;
341     sl->prev->next = sl->next;
342     sl->next = slot_first->next;
343     sl->prev = slot_first;
344     sl->next->prev = sl;
345     sl->prev->next = sl;
346     /* scan through this memory and pick all the slots which are still leaking
347        and add them to the inProgress list */
348     if (sl->extraStack != NULL && sl->extraStack->protectedMemory != NULL) mprotect(sl->extraStack->protectedMemory, sl->extraStack->protectedMemoryLength, PROT_READ);
349     for (scanner = ((char*)sl)+sizeof(Slot); scanner < ((char*)sl)+sizeof(Slot)+sl->userSize-sizeof(char*)+1; scanner+=sizeof(char*)) {
350       fnd = (Slot**)CkHashtableGet(table, scanner);
351       //if (fnd != NULL) printf("scanning heap %p, %d\n",*fnd,isLeakSlot(*fnd));
352       if (fnd != NULL && isLeakSlot(*fnd)) {
353         found = *fnd;
354         /* mark slot as not leak */
355         //printf("heap pointing to %p\n",found+1);
356         found->magic &= ~LEAK_FLAG;
357         /* move the slot a inProgress */
358         found->next->prev = found->prev;
359         found->prev->next = found->next;
360         found->next = inProgress.next;
361         found->prev = &inProgress;
362         found->next->prev = found;
363         found->prev->next = found;
364       }
365     }
366     if (sl->extraStack != NULL && sl->extraStack->protectedMemory != NULL) mprotect(sl->extraStack->protectedMemory, sl->extraStack->protectedMemoryLength, PROT_NONE);
367   }
368
369   // Step 4)
370   // move back all the entries in leaking to slot_first
371   if (leaking.next != &leaking) {
372     leaking.next->prev = slot_first;
373     leaking.prev->next = slot_first->next;
374     slot_first->next->prev = leaking.prev;
375     slot_first->next = leaking.next;
376   }
377
378
379   // mark all the entries in the leaking list as leak, and put them back
380   // into the main list
381   /*sl = leaking.next;
382   while (sl != &leaking) {
383     sl->magic | LEAK_FLAG;
384   }
385   if (leaking.next != &leaking) {
386     slot_first->next->prev = leaking.prev;
387     leaking.prev->next = slot_first->next;
388     leaking.next->prev = slot_first;
389     slot_first->next = leaking.next;
390   }  
391   */
392
393   CkDeleteHashtable(table);
394 }
395
396 /****************** memory allocation tree ******************/
397
398 /* This allows the representation and creation of a tree where each node
399  * represents a line in the code part of a stack trace of a malloc. The node
400  * contains how much data has been allocated starting from that line of code,
401  * down the stack.
402  */
403
404 typedef struct _AllocationPoint AllocationPoint;
405
406 struct _AllocationPoint {
407   /* The stack pointer this allocation refers to */
408   void * key;
409   /* Pointer to the parent AllocationPoint of this AllocationPoint in the tree */
410   AllocationPoint * parent;
411   /* Pointer to the first child AllocationPoint in the tree */
412   AllocationPoint * firstChild;
413   /* Pointer to the sibling of this AllocationPoint (i.e the next child of the parent) */
414   AllocationPoint * sibling;
415   /* Pointer to the next AllocationPoint with the same key.
416    * There can be more than one AllocationPoint with the same key because the
417    * parent can be different. Used only in the hashtable. */
418   AllocationPoint * next;
419   /* Size of the memory allocate */
420   int size;
421   /* How many blocks have been allocated from this point */
422   int count;
423   /* Flags pertaining to the allocation point, currently only LEAK_FLAG */
424   char flags;
425 };
426
427 // pup a single AllocationPoint. The data structure must be already allocated
428 void pupAllocationPointSingle(pup_er p, AllocationPoint *node, int *numChildren) {
429   pup_pointer(p, &node->key);
430   pup_int(p, &node->size);
431   pup_int(p, &node->count);
432   pup_char(p, &node->flags);
433   *numChildren = 0;
434   AllocationPoint *child;
435   for (child = node->firstChild; child != NULL; child = child->sibling) (*numChildren) ++;
436   pup_int(p, numChildren);
437  
438 }
439
440 // TODO: the following pup does not work for unpacking!
441 void pupAllocationPoint(pup_er p, void *data) {
442   AllocationPoint *node = (AllocationPoint*)data;
443   int numChildren;
444   pupAllocationPointSingle(p, node, &numChildren);
445   AllocationPoint *child;
446   for (child = node->firstChild; child != NULL; child = child->sibling) {
447     pupAllocationPoint(p, child);
448   }
449 }
450
451 void deleteAllocationPoint(void *ptr) {
452   AllocationPoint *node = (AllocationPoint*)ptr;
453   AllocationPoint *child;
454   for (child = node->firstChild; child != NULL; child = child->sibling) deleteAllocationPoint(child);
455   mm_free(node);
456 }
457
458 void printAllocationTree(AllocationPoint *node, FILE *fd, int depth) {
459   int i;
460   if (node==NULL) return;
461   int numChildren = 0;
462   AllocationPoint *child;
463   for (child = node->firstChild; child != NULL; child = child->sibling) numChildren ++; 
464   for (i=0; i<depth; ++i) fprintf(fd, " ");
465   fprintf(fd, "node %p: bytes=%d, count=%d, child=%d\n",node->key,node->size,node->count,numChildren);
466   printAllocationTree(node->sibling, fd, depth);
467   printAllocationTree(node->firstChild, fd, depth+2);
468 }
469
470 AllocationPoint * CreateAllocationTree(int *nodesCount) {
471   Slot *scanner;
472   CkHashtable_c table;
473   int i, new;
474   AllocationPoint *parent, **start, *cur;
475   AllocationPoint *root = NULL;
476   int numNodes = 0;
477   
478   scanner=slot_first->next;
479   table = CkCreateHashtable_pointer(sizeof(char *), 10000);
480
481   for ( ; scanner!=slot_first; scanner=scanner->next) {
482     parent = NULL;
483     for (i=scanner->stackLen-1; i>=0; --i) {
484       new = 0;
485       start = CkHashtableGet(table, &scanner->from[i]);
486       if (start == NULL) {
487         cur = (AllocationPoint*) mm_malloc(sizeof(AllocationPoint));
488         numNodes ++;
489         new = 1;
490         cur->next = cur;
491         *(AllocationPoint**)CkHashtablePut(table, &scanner->from[i]) = cur;
492       } else {
493         for (cur = (*start)->next; cur != *start && cur->parent != parent; cur = cur->next);
494         if (cur->parent != parent) {
495           cur = (AllocationPoint*) mm_malloc(sizeof(AllocationPoint));
496           numNodes ++;
497           new = 1;
498           cur->next = (*start)->next;
499           (*start)->next = cur;
500         }
501       }
502       // here "cur" points to the correct AllocationPoint for this stack frame
503       if (new) {
504         cur->key = scanner->from[i];
505         cur->parent = parent;
506         cur->size = 0;
507         cur->count = 0;
508         cur->flags = 0;
509         cur->firstChild = NULL;
510         if (parent == NULL) {
511           cur->sibling = NULL;
512           CmiAssert(root == NULL);
513           root = cur;
514         } else {
515           cur->sibling = parent->firstChild;
516           parent->firstChild = cur;
517         }
518       }
519       cur->size += scanner->userSize;
520       cur->count ++;
521       cur->flags |= isLeakSlot(scanner);
522       parent = cur;
523     }
524   }
525   
526   char filename[100];
527   sprintf(filename, "allocationTree_%d", CmiMyPe());
528   FILE *fd = fopen(filename, "w");
529   fprintf(fd, "digraph %s {\n", filename);
530   CkHashtableIterator_c it = CkHashtableGetIterator(table);
531   AllocationPoint **startscan, *scan;
532   while ((startscan=CkHashtableIteratorNext(it,NULL))!=NULL) {
533     fprintf(fd, "\t\"n%p\" [label=\"%p\\nsize=%d\\ncount=%d\"];\n",*startscan,(*startscan)->key,
534           (*startscan)->size,(*startscan)->count);
535     for (scan = (*startscan)->next; scan != *startscan; scan = scan->next) {
536       fprintf(fd, "\t\"n%p\" [label=\"%p\\nsize=%d\\ncount=%d\"];\n",scan,scan->key,scan->size,scan->count);
537     }
538   }
539   CkHashtableIteratorSeekStart(it);
540   while ((startscan=CkHashtableIteratorNext(it,NULL))!=NULL) {
541     fprintf(fd, "\t\"n%p\" -> \"n%p\";\n",(*startscan)->parent,(*startscan));
542     for (scan = (*startscan)->next; scan != *startscan; scan = scan->next) {
543       fprintf(fd, "\t\"n%p\" -> \"n%p\";\n",scan->parent,scan);
544     }
545   }
546   fprintf(fd, "}\n");
547   fclose(fd);
548   
549   sprintf(filename, "allocationTree_%d.tree", CmiMyPe());
550   fd = fopen(filename, "w");
551   printAllocationTree(root, fd, 0);
552   fclose(fd);
553  
554   CkDeleteHashtable(table);
555   if (nodesCount != NULL) *nodesCount = numNodes;
556   return root;
557 }
558
559 void MergeAllocationTreeSingle(AllocationPoint *node, AllocationPoint *remote) {
560   
561 }
562
563 void * MergeAllocationTree(void *data, void **remoteData, int numRemote) {
564   int i;
565   for (i=0; i<numRemote; ++i) MergeAllocationTreeSingle((AllocationPoint*)data, (AllocationPoint*)remoteData[i]);
566   return data;
567 }
568
569 /*
570
571 / *Head of the current circular allocated block list* /
572 Slot slot_first_storage={&slot_first_storage,&slot_first_storage};
573 Slot *slot_first=&slot_first_storage;
574
575 #define CMI_MEMORY_ROUTINES 1
576
577 / * Mark all allocated memory as being OK * /
578 void CmiMemoryMark(void) {
579         CmiMemLock();
580         / * Just make a new linked list of slots * /
581         slot_first=(Slot *)mm_malloc(sizeof(Slot));
582         slot_first->next=slot_first->prev=slot_first;
583         CmiMemUnlock();
584 }
585
586 / * Mark this allocated block as being OK * /
587 void CmiMemoryMarkBlock(void *blk) {
588         Slot *s=Slot_fmUser(blk);
589         CmiMemLock();
590         if (s->magic!=SLOTMAGIC) CmiAbort("CmiMemoryMarkBlock called on non-malloc'd block!\n");
591         / * Splice us out of the current linked list * /
592         s->next->prev=s->prev;
593         s->prev->next=s->next;
594         s->prev=s->next=s; / * put us in our own list * /
595         CmiMemUnlock();
596 }
597
598 / * Print out all allocated memory * /
599 void CmiMemorySweep(const char *where) {
600         Slot *cur;
601         int nBlocks=0,nBytes=0;
602         CmiMemLock();
603         cur=slot_first->next;
604         CmiPrintf("[%d] ------- LEAK CHECK: %s -----\n",CmiMyPe(), where);
605         while (cur!=slot_first) {
606                 printSlot(cur);
607                 nBlocks++; nBytes+=cur->userSize;
608                 cur=cur->next;
609         }
610         if (nBlocks) {
611                 CmiPrintf("[%d] Total leaked memory: %d blocks, %d bytes\n",
612                         CmiMyPe(),nBlocks,nBytes);
613                 / * CmiAbort("Memory leaks detected!\n"); * /
614         }
615         CmiMemUnlock();
616         CmiMemoryMark();
617 }
618 void CmiMemoryCheck(void) {}
619 */
620
621
622 /********** Allocation/Free ***********/
623
624 static int memoryTraceDisabled = 0;
625 #define MAX_STACK_FRAMES   2048
626 static int numStackFrames; // the number of frames presetn in stackFrames - 4 (this number is trimmed at 0
627 static void *stackFrames[MAX_STACK_FRAMES];
628
629 /* Write a valid slot to this field */
630 static void *setSlot(Slot *s,int userSize) {
631   char *user=SlotToUser(s);
632   
633   /* Splice into the slot list just past the head */
634   s->next=slot_first->next;
635   s->prev=slot_first;
636   s->next->prev=s;
637   s->prev->next=s;
638   
639   /* Set the last 4 bits of magic to classify the memory together with the magic */
640   s->magic=SLOTMAGIC + (memory_status_info>0? USER_TYPE : SYSTEM_TYPE);
641   //if (memory_status_info>0) printf("user allocation\n");
642   s->userSize=userSize;
643   s->extraStack=(SlotStack *)0;
644
645   /* Set the stack frames */
646   s->stackLen=numStackFrames;
647   s->from=(void**)(user+userSize);
648   memcpy(s->from, &stackFrames[4], numStackFrames*sizeof(void*));
649   
650   return (void *)user;
651 }
652
653 /* Delete this slot structure */
654 static void freeSlot(Slot *s) {
655   /* Splice out of the slot list */
656   s->next->prev=s->prev;
657   s->prev->next=s->next;
658   s->prev=s->next=(Slot *)0;//0x0F00; why was it not 0?
659
660   s->magic=SLOTMAGIC_FREED;
661   s->userSize=-1;
662 }
663
664 void dumpStackFrames() {
665   numStackFrames=MAX_STACK_FRAMES;
666   if (memoryTraceDisabled==0) {
667     memoryTraceDisabled = 1;
668     CmiBacktraceRecordHuge(stackFrames,&numStackFrames);
669     memoryTraceDisabled = 0;
670     numStackFrames-=4;
671     if (numStackFrames < 0) numStackFrames = 0;
672   } else {
673     numStackFrames=0;
674     stackFrames[0] = (void*)0;
675   }
676 }
677
678 /********** meta_ routines ***********/
679
680 /* Return the system page size */
681 static int meta_getpagesize(void) {
682   static int cache=0;
683 #if defined(CMK_GETPAGESIZE_AVAILABLE)
684   if (cache==0) cache=getpagesize();
685 #else
686   if (cache==0) cache=8192;
687 #endif
688   return cache;
689 }
690
691 /* Only display startup status messages from processor 0 */
692 static void status(char *msg) {
693   if (CmiMyPe()==0 && !CmiArgGivingUsage()) {
694     CmiPrintf("%s",msg);
695   }
696 }
697
698 extern int getCharmEnvelopeSize();
699
700 static void meta_init(char **argv) {
701   status("Converse -memory mode: charmdebug\n");
702   char buf[100];
703   sprintf(buf,"slot size %d\n",sizeof(Slot));
704   status(buf);
705   charmEnvelopeSize = getCharmEnvelopeSize();
706   CpdDebugGetAllocationTree = CreateAllocationTree;
707   CpdDebug_pupAllocationPoint = pupAllocationPoint;
708   CpdDebug_deleteAllocationPoint = deleteAllocationPoint;
709   CpdDebug_MergeAllocationTree = MergeAllocationTree;
710 }
711
712 static void *meta_malloc(size_t size) {
713   dumpStackFrames();
714   Slot *s=(Slot *)mm_malloc(sizeof(Slot)+size+numStackFrames*sizeof(void*));
715   char *user = (char*)s;
716   if (s!=NULL) user = setSlot(s,size);
717   traceMalloc_c(user, size, s->from, s->stackLen);
718   return user;
719 }
720
721 static void meta_free(void *mem) {
722   Slot *s;
723   traceFree_c(mem);
724   if (mem==NULL) return; /*Legal, but misleading*/
725
726   s=((Slot *)mem)-1;
727   if ((s->magic&~FLAGS_MASK)==SLOTMAGIC_VALLOC)
728   { /*Allocated with special alignment*/
729     freeSlot(s);
730     mm_free(s->extraStack);
731     /*mm_free(((char *)mem)-meta_getpagesize());*/
732   }
733   else if ((s->magic&~FLAGS_MASK)==SLOTMAGIC) 
734   { /*Ordinary allocated block */
735     freeSlot(s);
736     mm_free(s);
737   }
738   else if (s->magic==SLOTMAGIC_FREED)
739     CmiAbort("Free'd block twice");
740   else /*Unknown magic number*/
741     CmiAbort("Free'd non-malloc'd block");
742 }
743
744 static void *meta_calloc(size_t nelem, size_t size) {
745   void *area=meta_malloc(nelem*size);
746   memset(area,0,nelem*size);
747   return area;
748 }
749
750 static void meta_cfree(void *mem) {
751   meta_free(mem);
752 }
753
754 static void *meta_realloc(void *oldBuffer, size_t newSize) {
755   void *newBuffer = meta_malloc(newSize);
756   if ( newBuffer && oldBuffer ) {
757     /*Preserve old buffer contents*/
758     Slot *o=UserToSlot(oldBuffer);
759     size_t size=o->userSize;
760     if (size>newSize) size=newSize;
761     if (size > 0)
762       memcpy(newBuffer, oldBuffer, size);
763
764     meta_free(oldBuffer);
765   }
766   return newBuffer;
767 }
768
769 static void *meta_memalign(size_t align, size_t size) {
770   int overhead = align;
771   while (overhead < sizeof(Slot)+sizeof(SlotStack)) overhead += align;
772   /* Allocate the required size + the overhead needed to keep the user alignment */
773   dumpStackFrames();
774   
775   char *alloc=(char *)mm_memalign(align,overhead+size+numStackFrames*sizeof(void*));
776   Slot *s=(Slot *)(alloc+overhead-sizeof(Slot));  
777   void *user=setSlot(s,size);
778   s->magic = SLOTMAGIC_VALLOC + (s->magic&0xF);
779   s->extraStack = (SlotStack *)alloc; /* use the extra space as stack */
780   s->extraStack->protectedMemory = NULL;
781   s->extraStack->protectedMemoryLength = 0;
782   traceMalloc_c(user, size, s->from, s->stackLen);
783   return user;  
784 }
785
786 static void *meta_valloc(size_t size) {
787   return meta_memalign(meta_getpagesize(),size);
788 }
789
790 void setProtection(char* mem, char *ptr, int len, int flag) {
791   Slot *sl = (Slot*)(mem-sizeof(Slot));
792   if (sl->extraStack == NULL) CmiAbort("Tried to protect memory not memaligned\n");
793   if (flag != 0) {
794     sl->extraStack->protectedMemory = ptr;
795     sl->extraStack->protectedMemoryLength = len;
796   } else {
797     sl->extraStack->protectedMemory = NULL;
798     sl->extraStack->protectedMemoryLength = 0;
799   }
800 }
801
802 void setMemoryTypeChare(void *ptr) {
803   Slot *sl = UserToSlot(ptr);
804   sl->magic = (sl->magic & ~FLAGS_MASK) | CHARE_TYPE;
805 }
806
807 /* The input parameter is the pointer to the envelope, after the CmiChunkHeader */
808 void setMemoryTypeMessage(void *ptr) {
809   void *realptr = (char*)ptr - sizeof(CmiChunkHeader);
810   Slot *sl = UserToSlot(realptr);
811   if ((sl->magic&~FLAGS_MASK) == SLOTMAGIC || (sl->magic&~FLAGS_MASK) == SLOTMAGIC_VALLOC) {
812     sl->magic = (sl->magic & ~FLAGS_MASK) | MESSAGE_TYPE;
813   }
814 }