Route ampif77 and ampif90 through ampiCC, factoring out duplicated code
[charm.git] / src / conv-core / memory-paranoid.c
blobe6c98373d3c033b6f496112b68e760b35f4f1e59
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.
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.
13 * This version of malloc() should not be linked into production software,
14 * since it increases the time and memory overhead of malloc().
17 static void memAbort(const char *err, void *ptr)
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
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;
38 * Struct Slot contains all of the information about a malloc buffer except
39 * for the contents of its memory.
41 struct _Slot {
42 /*Doubly-linked allocated block list*/
43 struct _Slot *next;
44 struct _Slot *prev;
46 /*The number of bytes of user data*/
47 int userSize;
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;
55 /* Controls the number of stack frames to print out */
56 #define STACK_LEN 4
57 void *from[STACK_LEN];
59 /*Padding to detect writes before and after buffer*/
60 #define PADLEN 72 /*Bytes of padding at start and end of buffer*/
61 char pad[PADLEN];
63 typedef struct _Slot Slot;
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);
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)
79 int fill=memory_fill;
80 int 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);
89 /*Convert a slot to a user address*/
90 static char *Slot_toUser(Slot *s) {
91 return ((char *)s)+sizeof(Slot);
94 /*Head of the circular slot list*/
95 static Slot slot_first={&slot_first,&slot_first};
98 /********* Heap Checking ***********/
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*/
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));
112 /*Check these padding bytes*/
113 static void checkPad(const char *pad, const char *errMsg, const 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);
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;
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);
153 checkPad(s->pad,"Corruption before start of block",user,s);
154 checkPad(user+s->userSize,"Corruption after block",user,s);
157 /*Check the entire heap for consistency*/
158 void memory_check(void)
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;
169 if (memory_verbose)
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));
178 #define CMI_MEMORY_ROUTINES 1
180 /* Mark all allocated memory as being OK */
181 void CmiMemoryMark(void) { }
182 void CmiMemoryMarkBlock(void *blk) { }
183 void CmiMemorySweep(const char *where) { }
185 void CmiMemoryCheck(void)
187 memory_check();
190 /********** Allocation/Free ***********/
192 static int memoryTraceDisabled = 0;
194 /*Write a valid slot to this field*/
195 static void *setSlot(Slot *s,int userSize) {
196 char *user=Slot_toUser(s);
198 /*Determine if it's time for a heap check*/
199 if ((++memory_checkphase)>=memory_checkfreq) memory_check();
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;
207 s->magic=SLOTMAGIC;
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;
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;
228 /*Delete this slot structure*/
229 static void freeSlot(Slot *s) {
230 checkSlot(s);
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;
237 s->magic=SLOTMAGIC_FREED;
238 fill_uninit(Slot_toUser(s),s->userSize);
239 s->userSize=-1;
241 /*Determine if it's time for a heap check*/
242 if ((++memory_checkphase)>=memory_checkfreq) memory_check();
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;
254 /********** meta_ routines ***********/
256 #if ! CMK_MEMORY_BUILD_OS
257 /* Use Gnumalloc as meta-meta malloc fallbacks (mm_*) */
258 #include "memory-gnu.c"
259 #endif
261 /*Only display startup status messages from processor 0*/
262 static void status(const char *msg) {
263 if (CmiMyPe()==0 && !CmiArgGivingUsage()) {
264 CmiPrintf("%s",msg);
267 static void meta_init(char **argv)
269 if (CmiMyRank()==0) CmiMemoryIs_flag|=CMI_MEMORY_IS_PARANOID;
270 CmiArgGroup("Converse","memory-paranoid");
271 status("Converse -memory mode: paranoid");
272 /*Parse uninitialized-memory-fill options:*/
273 int memory_fill_value;
274 if (CmiGetArgIntDesc(argv,"+memory_fill",&memory_fill_value, "Overwrite new and deleted memory")) {
275 if (CmiMyRank()==0) {
276 memory_fill = memory_fill_value;
278 status(" fill");
280 if (CmiGetArgFlagDesc(argv,"+memory_fillphase", "Invert memory overwrite pattern")) {
281 if (CmiMyRank()==0) {
282 memory_fillphase=1;
284 status(" phaseflip");
286 /*Parse heap-check options*/
287 int memory_checkfreq_value;
288 if (CmiGetArgIntDesc(argv,"+memory_checkfreq",&memory_checkfreq_value, "Check heap this many mallocs")) {
289 if (CmiMyRank()==0) {
290 memory_checkfreq = memory_checkfreq_value;
292 status(" checkfreq");
294 if (CmiGetArgFlagDesc(argv,"+memory_verbose", "Give a printout at each heap check")) {
295 if (CmiMyRank()==0) {
296 memory_verbose=1;
298 status(" verbose");
300 status("\n");
303 static void *meta_malloc(size_t size)
305 Slot *s=(Slot *)mm_malloc(sizeof(Slot)+size+PADLEN);
306 if (s==NULL) return s;
307 return setSlot(s,size);
310 static void meta_free(void *mem)
312 Slot *s;
313 if (mem==NULL) return; /*Legal, but misleading*/
314 if (badPointer((Slot *)mem))
315 memAbort("Free'd near-NULL block",mem);
317 s=((Slot *)mem)-1;
318 if (s->magic==SLOTMAGIC_VALLOC)
319 { /*Allocated with special alignment*/
320 freeSlot(s);
321 mm_free(((char *)mem)-CmiGetPageSize());
323 else if (s->magic==SLOTMAGIC)
324 { /*Ordinary allocated block */
325 freeSlot(s);
326 mm_free(s);
328 else if (s->magic==SLOTMAGIC_FREED)
329 memAbort("Free'd block twice",mem);
330 else /*Unknown magic number*/
331 memAbort("Free'd non-malloc'd block",mem);
334 static void *meta_calloc(size_t nelem, size_t size)
336 void *area=meta_malloc(nelem*size);
337 if (area != NULL) memset(area,0,nelem*size);
338 return area;
341 static void meta_cfree(void *mem)
343 meta_free(mem);
346 static void *meta_realloc(void *oldBuffer, size_t newSize)
348 void *newBuffer = meta_malloc(newSize);
349 if ( newBuffer && oldBuffer ) {
350 /*Preserve old buffer contents*/
351 Slot *o=Slot_fmUser(oldBuffer);
352 size_t size=o->userSize;
353 if (size>newSize) size=newSize;
354 if (size > 0)
355 memcpy(newBuffer, oldBuffer, size);
357 if (oldBuffer)
358 meta_free(oldBuffer);
359 return newBuffer;
362 static void *meta_memalign(size_t align, size_t size)
364 /*Allocate a whole extra page for our slot structure*/
365 char *alloc=(char *)mm_memalign(align,CmiGetPageSize()+size+PADLEN);
366 Slot *s=(Slot *)(alloc+CmiGetPageSize()-sizeof(Slot));
367 void *user=setSlot(s,size);
368 s->magic=SLOTMAGIC_VALLOC;
369 return user;
372 static int meta_posix_memalign(void **outptr, size_t align, size_t size)
374 /*Allocate a whole extra page for our slot structure*/
375 int ret = mm_posix_memalign(outptr,align,CmiGetPageSize()+size+PADLEN);
376 if (ret != 0)
377 return ret;
378 char *alloc=(char *)*outptr;
379 Slot *s=(Slot *)(alloc+CmiGetPageSize()-sizeof(Slot));
380 void *user=setSlot(s,size);
381 s->magic=SLOTMAGIC_VALLOC;
382 *outptr = user;
383 return 0;
386 static void *meta_aligned_alloc(size_t align, size_t size)
388 /*Allocate a whole extra page for our slot structure*/
389 char *alloc=(char *)mm_aligned_alloc(align,CmiGetPageSize()+size+PADLEN);
390 Slot *s=(Slot *)(alloc+CmiGetPageSize()-sizeof(Slot));
391 void *user=setSlot(s,size);
392 s->magic=SLOTMAGIC_VALLOC;
393 return user;
396 static void *meta_valloc(size_t size)
398 return meta_memalign(CmiGetPageSize(),size);
401 static void *meta_pvalloc(size_t size)
403 const size_t pagesize = CmiGetPageSize();
404 return meta_memalign(pagesize, (size + pagesize - 1) & ~(pagesize - 1));