2 * Orion's debugging malloc(), olawlor@acm.org, 1/11/2001
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
)
21 CmiPrintf("[%d] memory-paranoid> FATAL HEAP ERROR! %s (block %p)\n",
23 CmiAbort("memory-paranoid> FATAL HEAP ERROR");
25 /*Simple printf version*/
26 fprintf(stderr
,"memory-paranoid> FATAL HEAP ERROR! %s (block %p)\n",
28 fflush(stdout
);fflush(stderr
);
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.
42 /*Doubly-linked allocated block list*/
46 /*The number of bytes of user data*/
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
55 /* Controls the number of stack frames to print out */
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*/
63 typedef struct _Slot Slot
;
66 #define PADFN(i) (char)(217+(i))
67 /*Write these padding bytes*/
68 static void setPad(char *pad
) {
70 for (i
=0;i
<PADLEN
;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
)
81 if (fill
==-1) /*Alternate zero and DE fill*/
82 fill
=(memory_fillphase
++)%2;
83 if (fill
!=0) fillChar
=0xDE;
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
) {
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");
129 /*Check if this pointer is "bad"-- not in the heap.*/
130 static int badPointer(Slot
*p
) {
132 if ((c
<(char *)0x1000) || (c
+0x1000)<(char *)0x1000)
137 /*Check this slot for consistency*/
138 static void checkSlot(Slot
*s
) {
139 char *user
=Slot_toUser(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
);
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;
163 while (cur
!=&slot_first
) {
166 nBytes
+=cur
->userSize
;
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)
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
;
210 if (memoryTraceDisabled
==0) {
211 memoryTraceDisabled
= 1;
212 CmiBacktraceRecord(s
->from
,3,&n
);
213 memoryTraceDisabled
= 0;
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*/
228 /*Delete this slot structure*/
229 static void freeSlot(Slot
*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
);
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
));
254 /********** meta_ routines ***********/
256 #if ! CMK_MEMORY_BUILD_OS
257 /* Use Gnumalloc as meta-meta malloc fallbacks (mm_*) */
258 #include "memory-gnu.c"
261 /*Only display startup status messages from processor 0*/
262 static void status(const char *msg
) {
263 if (CmiMyPe()==0 && !CmiArgGivingUsage()) {
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
;
280 if (CmiGetArgFlagDesc(argv
,"+memory_fillphase", "Invert memory overwrite pattern")) {
281 if (CmiMyRank()==0) {
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) {
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
)
313 if (mem
==NULL
) return; /*Legal, but misleading*/
314 if (badPointer((Slot
*)mem
))
315 memAbort("Free'd near-NULL block",mem
);
318 if (s
->magic
==SLOTMAGIC_VALLOC
)
319 { /*Allocated with special alignment*/
321 mm_free(((char *)mem
)-CmiGetPageSize());
323 else if (s
->magic
==SLOTMAGIC
)
324 { /*Ordinary allocated block */
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
);
341 static void meta_cfree(void *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
;
355 memcpy(newBuffer
, oldBuffer
, size
);
358 meta_free(oldBuffer
);
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
;
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
);
378 char *alloc
=(char *)*outptr
;
379 Slot
*s
=(Slot
*)(alloc
+CmiGetPageSize()-sizeof(Slot
));
380 void *user
=setSlot(s
,size
);
381 s
->magic
=SLOTMAGIC_VALLOC
;
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
;
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));