doc: Add serial to list of ci file reserved words
[charm.git] / src / conv-core / memory-leak.c
1 /*
2  * Orion's debugging malloc(), olawlor@acm.org, 2003/9/7
3  * 
4  * This is a special version of malloc() and company for debugging software
5  * that is suspected of leaking memory.
6  *
7  * The basic usage is:
8  *    1.) Do your startup
9  *    2.) Call memory_mark(), which marks all allocated memory as OK.
10  *    3.) Do the work you think is leaking memory.
11  *    4.) Call memory_sweep(), which prints out any mallocs since the 
12  *        last sweep or mark.
13  *
14  * This version of malloc() only introduces a small constant amount
15  * of slowdown per malloc/free.
16  */
17
18 #if ! CMK_MEMORY_BUILD_OS
19 /* Use Gnumalloc as meta-meta malloc fallbacks (mm_*) */
20 #include "memory-gnuold.c"
21 #endif
22
23
24 typedef struct Slot Slot;
25 /*
26  * Struct Slot contains all of the information about a malloc buffer except
27  * for the contents of its memory.
28  */
29 struct Slot {
30 /*Doubly-linked allocated block list*/
31         Slot *next;
32         Slot *prev;
33         
34 /*The number of bytes of user data*/
35         int userSize;
36
37 /*A magic number field, to verify this is an actual malloc'd buffer*/
38 #define SLOTMAGIC 0x8402a5f5
39 #define SLOTMAGIC_VALLOC 0x7402a5f5
40 #define SLOTMAGIC_FREED 0xDEADBEEF
41         int  magic;
42
43 /* Controls the number of stack frames to print out */
44 #define STACK_LEN 8
45         void *from[STACK_LEN];
46 };
47
48 /*Convert a slot to a user address*/
49 static char *Slot_toUser(Slot *s) {
50         return ((char *)s)+sizeof(Slot);
51 }
52
53 /*Convert a user address to a slot*/
54 static Slot *Slot_fmUser(void *user) {
55         char *cu=(char *)user;
56         Slot *s=(Slot *)(cu-sizeof(Slot));
57         return s;
58 }
59
60 static void printSlot(Slot *s) {
61         CmiPrintf("[%d] Leaked block of %d bytes at %p:\n",
62                 CmiMyPe(), s->userSize, Slot_toUser(s));
63         CmiBacktracePrint(s->from,STACK_LEN);
64 }
65
66 /********* Heap Checking ***********/
67
68 /*Head of the current circular allocated block list*/
69 Slot slot_first_storage={&slot_first_storage,&slot_first_storage};
70 Slot *slot_first=&slot_first_storage;
71
72 #define CMI_MEMORY_ROUTINES 1
73
74 /* Mark all allocated memory as being OK */
75 void CmiMemoryMark(void) {
76         CmiMemLock();
77         /* Just make a new linked list of slots */
78         slot_first=(Slot *)mm_malloc(sizeof(Slot));
79         slot_first->next=slot_first->prev=slot_first;
80         CmiMemUnlock();
81 }
82
83 /* Mark this allocated block as being OK */
84 void CmiMemoryMarkBlock(void *blk) {
85         Slot *s=Slot_fmUser(blk);
86         CmiMemLock();
87         if (s->magic!=SLOTMAGIC) CmiAbort("CmiMemoryMarkBlock called on non-malloc'd block!\n");
88         /* Splice us out of the current linked list */
89         s->next->prev=s->prev;
90         s->prev->next=s->next;
91         s->prev=s->next=s; /* put us in our own list */
92         CmiMemUnlock();
93 }
94
95 /* Print out all allocated memory */
96 void CmiMemorySweep(const char *where)
97 {
98         Slot *cur;
99         int nBlocks=0,nBytes=0;
100         CmiMemLock();
101         cur=slot_first->next;
102         CmiPrintf("[%d] ------- LEAK CHECK: %s -----\n",CmiMyPe(), where);
103         while (cur!=slot_first) {
104                 printSlot(cur);
105                 nBlocks++; nBytes+=cur->userSize;
106                 cur=cur->next;
107         }
108         if (nBlocks) {
109                 CmiPrintf("[%d] Total leaked memory: %d blocks, %d bytes\n",
110                         CmiMyPe(),nBlocks,nBytes);
111                 /* CmiAbort("Memory leaks detected!\n"); */
112         }
113         CmiMemUnlock();
114         CmiMemoryMark();
115 }
116 void CmiMemoryCheck(void) {}
117
118 /********** Allocation/Free ***********/
119
120 static int memoryTraceDisabled = 0;
121
122 /*Write a valid slot to this field*/
123 static void *setSlot(Slot *s,int userSize) {
124         char *user=Slot_toUser(s);
125
126 /*Splice into the slot list just past the head*/
127         s->next=slot_first->next;
128         s->prev=slot_first;
129         s->next->prev=s;
130         s->prev->next=s;
131         
132         s->magic=SLOTMAGIC;
133         s->userSize=userSize;
134         {
135                 int n=STACK_LEN;
136                 if (memoryTraceDisabled==0) {
137                   memoryTraceDisabled = 1;
138                   CmiBacktraceRecord(s->from,3,&n);
139                   memoryTraceDisabled = 0;
140                 } else {
141                   s->from[0] = (void*)10;
142                   s->from[1] = (void*)9;
143                   s->from[2] = (void*)8;
144                   s->from[3] = (void*)7;
145                 }
146         }
147         return (void *)user;
148 }
149
150 /*Delete this slot structure*/
151 static void freeSlot(Slot *s) {
152 /*Splice out of the slot list*/
153         s->next->prev=s->prev;
154         s->prev->next=s->next;
155         s->prev=s->next=(Slot *)0x0F00;
156
157         s->magic=SLOTMAGIC_FREED;
158         s->userSize=-1;
159 }
160
161
162 /********** meta_ routines ***********/
163
164 /*Return the system page size*/
165 static int meta_getpagesize(void)
166 {
167         static int cache=0;
168 #if defined(CMK_GETPAGESIZE_AVAILABLE)
169         if (cache==0) cache=getpagesize();
170 #else
171         if (cache==0) cache=8192;
172 #endif
173         return cache;
174 }
175
176 /*Only display startup status messages from processor 0*/
177 static void status(char *msg) {
178   if (CmiMyPe()==0 && !CmiArgGivingUsage()) {
179     CmiPrintf("%s",msg);
180   }
181 }
182 static void meta_init(char **argv)
183 {
184   status("Converse -memory mode: leak");
185   status("\n");
186 }
187
188 static void *meta_malloc(size_t size)
189 {
190   Slot *s=(Slot *)mm_malloc(sizeof(Slot)+size);
191   if (s==NULL) return s;
192   return setSlot(s,size);
193 }
194
195 static void meta_free(void *mem)
196 {
197   Slot *s;
198   if (mem==NULL) return; /*Legal, but misleading*/
199
200   s=((Slot *)mem)-1;
201   if (s->magic==SLOTMAGIC_VALLOC)
202   { /*Allocated with special alignment*/
203     freeSlot(s);
204     mm_free(((char *)mem)-meta_getpagesize());
205   }
206   else if (s->magic==SLOTMAGIC) 
207   { /*Ordinary allocated block */
208     freeSlot(s);
209     mm_free(s);
210   }
211   else if (s->magic==SLOTMAGIC_FREED)
212     CmiAbort("Free'd block twice");
213   else /*Unknown magic number*/
214     CmiAbort("Free'd non-malloc'd block");
215 }
216
217 static void *meta_calloc(size_t nelem, size_t size)
218 {
219   void *area=meta_malloc(nelem*size);
220   if (area != NULL) memset(area,0,nelem*size);
221   return area;
222 }
223
224 static void meta_cfree(void *mem)
225 {
226   meta_free(mem);
227 }
228
229 static void *meta_realloc(void *oldBuffer, size_t newSize)
230 {
231   void *newBuffer = meta_malloc(newSize);
232   if ( newBuffer && oldBuffer ) {
233     /*Preserve old buffer contents*/
234     Slot *o=Slot_fmUser(oldBuffer);
235     size_t size=o->userSize;
236     if (size>newSize) size=newSize;
237     if (size > 0)
238       memcpy(newBuffer, oldBuffer, size);
239   }
240   if (oldBuffer)
241     meta_free(oldBuffer);
242   return newBuffer;
243 }
244
245 static void *meta_memalign(size_t align, size_t size)
246 {
247   /*Allocate a whole extra page for our slot structure*/
248   char *alloc=(char *)mm_memalign(align,meta_getpagesize()+size);
249   Slot *s=(Slot *)(alloc+meta_getpagesize()-sizeof(Slot));  
250   void *user=setSlot(s,size);
251   s->magic=SLOTMAGIC_VALLOC;
252   return user;  
253 }
254 static void *meta_valloc(size_t size)
255 {
256   return meta_memalign(meta_getpagesize(),size);
257 }