doc: Add serial to list of ci file reserved words
[charm.git] / src / conv-core / memory-paranoid.c
1 /*
2  * Orion's debugging malloc(), olawlor@acm.org, 1/11/2001
3  * 
4  * This is a special version of malloc() and company for debugging software
5  * that is suspected of overrunning or underrunning the boundaries of a
6  * malloc buffer, or touching free memory.
7  *
8  * Detects writes before allocated region, writes after allocated region,
9  * double-deletes, uninitialized reads; i.e., most heap-related crashing errors.
10  * Includes a "CmiMemoryCheck()" routine which can check the entire heap's
11  * consistency on command.
12  *
13  * This version of malloc() should not be linked into production software,
14  * since it increases the time and memory overhead of malloc().
15  */
16
17 static void memAbort(const char *err, void *ptr)
18 {
19 #if 1
20 /*Parallel version*/
21         CmiPrintf("[%d] memory-paranoid> FATAL HEAP ERROR!  %s (block %p)\n",
22                 CmiMyPe(),err,ptr);
23         CmiAbort("memory-paranoid> FATAL HEAP ERROR");
24 #else
25 /*Simple printf version*/
26         fprintf(stderr,"memory-paranoid> FATAL HEAP ERROR!  %s (block %p)\n",
27                 err,ptr);
28         fflush(stdout);fflush(stderr);
29         abort();
30 #endif
31 }
32
33 /*This is the largest block we reasonably expect anyone to allocate*/
34 #define MAX_BLOCKSIZE (1024*1024*512)   /* replaced by max_allocated */
35 static size_t max_allocated = 0;
36
37 /*
38  * Struct Slot contains all of the information about a malloc buffer except
39  * for the contents of its memory.
40  */
41 struct _Slot {
42 /*Doubly-linked allocated block list*/
43         struct _Slot *next;
44         struct _Slot *prev;
45
46 /*The number of bytes of user data*/
47         int  userSize;
48
49 /*A magic number field, to verify this is an actual malloc'd buffer*/
50 #define SLOTMAGIC 0x8402a5f5
51 #define SLOTMAGIC_VALLOC 0x7402a5f5
52 #define SLOTMAGIC_FREED 0xDEADBEEF
53         int  magic;
54         
55 /* Controls the number of stack frames to print out */
56 #define STACK_LEN 4
57         void *from[STACK_LEN];
58
59 /*Padding to detect writes before and after buffer*/
60 #define PADLEN 32 /*Bytes of padding at start and end of buffer*/
61         char pad[PADLEN];
62 };
63 typedef struct _Slot    Slot;
64
65
66 #define PADFN(i) (char)(217+(i))
67 /*Write these padding bytes*/
68 static void setPad(char *pad) {
69         int i;
70         for (i=0;i<PADLEN;i++)
71                 pad[i]=PADFN(i);
72 }
73
74 /*The given area is uninitialized-- fill it as such. */
75 static int memory_fill=-1; /*-1 (alternate), 0 (zeros), or 1 (DE)*/
76 static int memory_fillphase=0;
77 static void fill_uninit(char *loc,int len)
78 {
79         int fill=memory_fill;
80         char fillChar;
81         if (fill==-1) /*Alternate zero and DE fill*/
82                 fill=(memory_fillphase++)%2;
83         if (fill!=0) fillChar=0xDE;
84         else fillChar=0;
85         memset(loc,fillChar,len);
86 }
87
88
89 /*Convert a slot to a user address*/
90 static char *Slot_toUser(Slot *s) {
91         return ((char *)s)+sizeof(Slot);
92 }
93
94 /*Head of the circular slot list*/
95 static Slot slot_first={&slot_first,&slot_first};
96
97
98 /********* Heap Checking ***********/
99
100 static int memory_checkfreq=100; /*Check entire heap every this many malloc/frees*/
101 static int memory_checkphase=0; /*malloc/free counter*/
102 static int memory_verbose=0; /*Print out every time we check the heap*/
103
104 static void slotAbort(const char *why,Slot *s) {
105         memory_checkfreq=100000;
106         CmiPrintf("[%d] Error in block of %d bytes at %p, allocated from:\n",
107                 CmiMyPe(), s->userSize, Slot_toUser(s));
108         CmiBacktracePrint(s->from,STACK_LEN);
109         memAbort(why,Slot_toUser(s));
110 }
111
112 /*Check these padding bytes*/
113 static void checkPad(char *pad,char *errMsg,void *ptr,Slot *s) {
114         int i;
115         for (i=0;i<PADLEN;i++)
116                 if (pad[i]!=PADFN(i)) {
117                         memory_checkfreq=100000;
118                         fprintf(stderr,"Corrupted data:");
119                         for (i=0;i<PADLEN;i++) 
120                                 if (pad[i]!=PADFN(i))
121                                         fprintf(stderr," %02x",(unsigned
122 int)(unsigned char)pad[i]);
123                                 else fprintf(stderr," -");
124                         fprintf(stderr,"\n");
125                         slotAbort(errMsg,s);
126                 }
127 }
128
129 /*Check if this pointer is "bad"-- not in the heap.*/
130 static int badPointer(Slot *p) {
131         char *c=(char *)p;
132         if ((c<(char *)0x1000) || (c+0x1000)<(char *)0x1000)
133                 return 1;
134         return 0;
135 }
136
137 /*Check this slot for consistency*/
138 static void checkSlot(Slot *s) {
139         char *user=Slot_toUser(s);
140         if (badPointer(s))
141                 slotAbort("Non-heap pointer passed to checkSlot",s);
142         if (s->magic!=SLOTMAGIC && s->magic!=SLOTMAGIC_VALLOC)
143                 slotAbort("Corrupted slot magic number",s);
144         if (s->userSize<0)
145                 slotAbort("Corrupted (negative) user size field",s);
146         if (s->userSize>max_allocated)
147                 slotAbort("Corrupted (huge) user size field",s);
148         if (badPointer(s->prev) || (s->prev->next!=s))
149                 slotAbort("Corrupted back link",s);
150         if (badPointer(s->next) || (s->next->prev!=s))
151                 slotAbort("Corrupted forward link",s);
152
153         checkPad(s->pad,"Corruption before start of block",user,s);
154         checkPad(user+s->userSize,"Corruption after block",user,s);     
155 }
156
157 /*Check the entire heap for consistency*/
158 void memory_check(void)
159 {
160         Slot *cur=slot_first.next;
161         int nBlocks=0, nBytes=0;
162         memory_checkphase=0;
163         while (cur!=&slot_first) {
164                 checkSlot(cur);
165                 nBlocks++;
166                 nBytes+=cur->userSize;
167                 cur=cur->next;
168         }
169         if (memory_verbose)
170         {
171           int nMegs=nBytes/(1024*1024);
172           int nKb=(nBytes-(nMegs*1024*1024))/1024;
173           CmiPrintf("[%d] Heap checked-- clean. %d blocks / %d.%03d megs\n",
174                 CmiMyPe(),nBlocks,nMegs,(int)(nKb*1000.0/1024.0)); 
175         }
176 }
177
178 #define CMI_MEMORY_ROUTINES 1
179
180 /* Mark all allocated memory as being OK */
181 void CmiMemoryMark(void) { }
182 void CmiMemoryMarkBlock(void *blk) { }
183 void CmiMemorySweep(const char *where) { }
184
185 void CmiMemoryCheck(void)
186 {
187         memory_check();
188 }
189
190 /********** Allocation/Free ***********/
191
192 static int memoryTraceDisabled = 0;
193
194 /*Write a valid slot to this field*/
195 static void *setSlot(Slot *s,int userSize) {
196         char *user=Slot_toUser(s);
197
198 /*Determine if it's time for a heap check*/
199         if ((++memory_checkphase)>=memory_checkfreq) memory_check();
200
201 /*Splice into the slot list just past the head*/
202         s->next=slot_first.next;
203         s->prev=&slot_first;
204         s->next->prev=s;
205         s->prev->next=s;
206         
207         s->magic=SLOTMAGIC;
208         {
209                 int n=STACK_LEN;
210                 if (memoryTraceDisabled==0) {
211                   memoryTraceDisabled = 1;
212                   CmiBacktraceRecord(s->from,3,&n);
213                   memoryTraceDisabled = 0;
214                 } else {
215                   s->from[0] = (void*)10;
216                   s->from[1] = (void*)9;
217                   s->from[2] = (void*)8;
218                 }
219         }
220         s->userSize=userSize;
221         if (userSize > max_allocated) max_allocated = userSize;
222         setPad(s->pad); /*Padding before block*/
223         fill_uninit(user,s->userSize); /*Block*/        
224         setPad(user+s->userSize); /*Padding after block*/
225         return (void *)user;
226 }
227
228 /*Delete this slot structure*/
229 static void freeSlot(Slot *s) {
230         checkSlot(s);
231
232 /*Splice out of the slot list*/
233         s->next->prev=s->prev;
234         s->prev->next=s->next;
235         s->prev=s->next=(Slot *)0x0F0;
236
237         s->magic=SLOTMAGIC_FREED;
238         fill_uninit(Slot_toUser(s),s->userSize);        
239         s->userSize=-1;
240
241 /*Determine if it's time for a heap check*/
242         if ((++memory_checkphase)>=memory_checkfreq) memory_check();
243 }
244
245 /*Convert a user address to a slot*/
246 static Slot *Slot_fmUser(void *user) {
247         char *cu=(char *)user;
248         Slot *s=(Slot *)(cu-sizeof(Slot));
249         checkSlot(s);
250         return s;
251 }
252
253
254 /********** meta_ routines ***********/
255
256 #if ! CMK_MEMORY_BUILD_OS
257 /* Use Gnumalloc as meta-meta malloc fallbacks (mm_*) */
258 #if CMK_MALLOC_USE_GNUOLD_MALLOC
259 #include "memory-gnuold.c"
260 #else
261 #include "memory-gnu.c"
262 #endif
263 #endif
264
265 /*Return the system page size*/
266 static int meta_getpagesize(void)
267 {
268         static int cache=0;
269 #if defined(CMK_GETPAGESIZE_AVAILABLE)
270         if (cache==0) cache=getpagesize();
271 #else
272         if (cache==0) cache=8192;
273 #endif
274         return cache;
275 }
276
277 /*Only display startup status messages from processor 0*/
278 static void status(char *msg) {
279   if (CmiMyPe()==0 && !CmiArgGivingUsage()) {
280     CmiPrintf("%s",msg);
281   }
282 }
283 static void meta_init(char **argv)
284 {
285   CmiMemoryIs_flag|=CMI_MEMORY_IS_PARANOID;
286   CmiArgGroup("Converse","memory-paranoid");
287   status("Converse -memory mode: paranoid");
288   /*Parse uninitialized-memory-fill options:*/
289   if (CmiGetArgIntDesc(argv,"+memory_fill",&memory_fill, "Overwrite new and deleted memory")) { 
290     status(" fill");
291   }
292   if (CmiGetArgFlagDesc(argv,"+memory_fillphase", "Invert memory overwrite pattern")) { 
293     status(" phaseflip");
294     memory_fillphase=1;
295   }
296   /*Parse heap-check options*/
297   if (CmiGetArgIntDesc(argv,"+memory_checkfreq",&memory_checkfreq, "Check heap this many mallocs")) {
298     status(" checkfreq");
299   }
300   if (CmiGetArgFlagDesc(argv,"+memory_verbose", "Give a printout at each heap check")) {
301     status(" verbose");
302     memory_verbose=1;
303   }  
304   status("\n");
305 }
306
307 static void *meta_malloc(size_t size)
308 {
309   Slot *s=(Slot *)mm_malloc(sizeof(Slot)+size+PADLEN);
310   if (s==NULL) return s;
311   return setSlot(s,size);
312 }
313
314 static void meta_free(void *mem)
315 {
316   Slot *s;
317   if (mem==NULL) return; /*Legal, but misleading*/
318   if (badPointer((Slot *)mem))
319     memAbort("Free'd near-NULL block",mem);
320
321   s=((Slot *)mem)-1;
322   if (s->magic==SLOTMAGIC_VALLOC)
323   { /*Allocated with special alignment*/
324     freeSlot(s);
325     mm_free(((char *)mem)-meta_getpagesize());
326   }
327   else if (s->magic==SLOTMAGIC) 
328   { /*Ordinary allocated block */
329     freeSlot(s);
330     mm_free(s);
331   }
332   else if (s->magic==SLOTMAGIC_FREED)
333     memAbort("Free'd block twice",mem);
334   else /*Unknown magic number*/
335     memAbort("Free'd non-malloc'd block",mem);
336 }
337
338 static void *meta_calloc(size_t nelem, size_t size)
339 {
340   void *area=meta_malloc(nelem*size);
341   if (area != NULL) memset(area,0,nelem*size);
342   return area;
343 }
344
345 static void meta_cfree(void *mem)
346 {
347   meta_free(mem);
348 }
349
350 static void *meta_realloc(void *oldBuffer, size_t newSize)
351 {
352   void *newBuffer = meta_malloc(newSize);
353   if ( newBuffer && oldBuffer ) {
354     /*Preserve old buffer contents*/
355     Slot *o=Slot_fmUser(oldBuffer);
356     size_t size=o->userSize;
357     if (size>newSize) size=newSize;
358     if (size > 0)
359       memcpy(newBuffer, oldBuffer, size);
360   }
361   if (oldBuffer)
362     meta_free(oldBuffer);
363   return newBuffer;
364 }
365
366 static void *meta_memalign(size_t align, size_t size)
367 {
368   /*Allocate a whole extra page for our slot structure*/
369   char *alloc=(char *)mm_memalign(align,meta_getpagesize()+size+PADLEN);
370   Slot *s=(Slot *)(alloc+meta_getpagesize()-sizeof(Slot));  
371   void *user=setSlot(s,size);
372   s->magic=SLOTMAGIC_VALLOC;
373   return user;  
374 }
375 static void *meta_valloc(size_t size)
376 {
377   return meta_memalign(meta_getpagesize(),size);
378 }