1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is mozilla.org code.
16 * The Initial Developer of the Original Code is
18 * Portions created by the Initial Developer are Copyright (C) 1999
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "libmalloc.h"
49 extern r_debug _r_debug
;
61 void* __wrap_malloc(size_t);
62 void* __wrap_realloc(void*, size_t);
63 void __wrap_free(void*);
64 void* __wrap___builtin_new(size_t);
65 void __wrap___builtin_delete(void*);
66 void* __wrap___builtin_vec_new(size_t);
67 void __wrap___builtin_vec_delete(void*);
68 void* __wrap_PR_Malloc(size_t);
69 void* __wrap_PR_Calloc(size_t, size_t);
70 void* __wrap_PR_Realloc(void*, size_t);
71 void __wrap_PR_Free(void*);
75 static int gLogFD
= -1;
77 static int gFillCount
= 0;
79 #define MARKER0 0xFFFFFFFF
80 #define MARKER1 0xEEEEEEEE
81 #define MARKER2_0 0xD8D8D8D8
82 #define MARKER2_1 0xE8E8E8E8
84 #define PATTERN_BYTE 0xFE
85 #define FREE_PATTERN_BYTE 0xDE
89 size_t rawSize
; // user requested size
90 size_t size
; // size rounded up
98 //----------------------------------------------------------------------
101 static void CrawlStack(malloc_log_entry
* me
, jmp_buf jb
)
104 u_long
* bp
= (u_long
*) (jb
[0].__savearea
[JB_BP
]);
106 u_long
* bp
= (u_long
*) (jb
[0].__jmpbuf
[JB_BP
]);
110 while (numpcs
< MAX_STACK_CRAWL
) {
111 u_long
* nextbp
= (u_long
*) *bp
++;
113 if ((pc
< 0x08000000) || (pc
> 0x7fffffff) || (nextbp
< bp
)) {
117 me
->pcs
[numpcs
++] = (char*) pc
;
125 //----------------------------------------------------------------------
127 #if defined(linux) || defined(NTO)
128 static void DumpAddressMap()
130 int mfd
= open("malloc-map", O_CREAT
|O_WRONLY
|O_TRUNC
, 0666);
132 malloc_map_entry mme
;
133 link_map
* map
= _r_debug
.r_map
;
134 while (NULL
!= map
) {
135 if (0 != map
->l_addr
) {
136 mme
.nameLen
= strlen(map
->l_name
);
137 mme
.address
= map
->l_addr
;
138 write(mfd
, &mme
, sizeof(mme
));
139 write(mfd
, map
->l_name
, mme
.nameLen
);
141 write(1, map
->l_name
, mme
.nameLen
);
152 //----------------------------------------------------------------------
154 static int Verify(Header
* h
)
156 // Sanity check the header first
157 if ((h
->marker0
!= MARKER0
) ||
158 (h
->marker1
!= MARKER1
) ||
159 (h
->rawSize
> h
->size
)) {
164 // Sanity check the trailer second
165 Trailer
* t
= (Trailer
*) ((char*)(h
+ 1) + h
->size
);
166 if ((t
->marker2
[0] != MARKER2_0
) ||
167 (t
->marker2
[1] != MARKER2_1
)) {
172 // Verify there were no overruns
173 size_t fill
= h
->size
- h
->rawSize
;
175 unsigned char* cp
= ((unsigned char*)(h
+ 1)) + h
->rawSize
;
176 unsigned char* end
= cp
+ fill
;
178 unsigned char ch
= *cp
++;
179 if (ch
!= PATTERN_BYTE
) {
189 Log(int aType
, void* aAddr
, size_t aSize
, void* aOldAddr
)
193 me
.type
= (u_long
) aType
;
194 me
.address
= (u_long
) aAddr
;
195 me
.size
= (u_long
) aSize
;
196 me
.oldaddress
= (u_long
) aOldAddr
;
202 write(gLogFD
, &me
, sizeof(me
) - MAX_STACK_CRAWL
*sizeof(char*) +
203 me
.numpcs
*sizeof(char*));
207 MallocHook(size_t aSize
, u_long aLogType
)
209 size_t roundedSize
= aSize
;
210 roundedSize
= ((roundedSize
+ 4 + gFillCount
) >> 2) << 2;
212 void* ptr
= REAL_MALLOC(sizeof(Header
) + roundedSize
+ sizeof(Trailer
));
215 Header
* h
= (Header
*) ptr
;
217 h
->size
= roundedSize
;
218 h
->marker0
= MARKER0
;
219 h
->marker1
= MARKER1
;
221 ptr
= (void*) ((char*)(h
+1));
223 // Fill new memory with a pattern to help detect overruns and
224 // usage of un-written memory
225 memset(ptr
, PATTERN_BYTE
, roundedSize
);
227 Trailer
* t
= (Trailer
*) ((char*)ptr
+ roundedSize
);
228 t
->marker2
[0] = MARKER2_0
;
229 t
->marker2
[1] = MARKER2_1
;
231 if (LIBMALLOC_LOG
& gFlags
) {
232 Log(aLogType
, ptr
, aSize
, 0);
240 FreeHook(void* aAddr
, u_long aLogType
)
245 if (LIBMALLOC_LOG
& gFlags
) {
246 Log(aLogType
, aAddr
, 0, 0);
248 Header
* h
= (Header
*) ((char*)aAddr
- sizeof(Header
));
250 // Munge the header so that a dup-free will fail the verify
251 h
->marker0
= 0xDEADBEEF;
252 h
->marker1
= 0xDEADBEEF;
254 // Munge the body of the allocation so that if the user
255 // still has a live reference they get messed up
256 void* ptr
= (void*) ((char*)(h
+1));
257 memset(ptr
, FREE_PATTERN_BYTE
, h
->rawSize
);
259 if (0 == (LIBMALLOC_NOFREE
& gFlags
)) {
264 if (0 == (LIBMALLOC_NOFREE
& gFlags
)) {
271 ReallocHook(void* aOldAddr
, size_t aSize
)
274 return MallocHook(aSize
, malloc_log_malloc
);
276 Header
* oldh
= (Header
*) ((char*)aOldAddr
- sizeof(Header
));
278 return REAL_REALLOC(aOldAddr
, aSize
);
280 size_t oldSize
= oldh
->rawSize
;
282 size_t roundedSize
= aSize
;
283 roundedSize
= ((roundedSize
+ 4) >> 2) << 2;
285 void* ptr
= REAL_MALLOC(sizeof(Header
) + roundedSize
+ sizeof(Trailer
));
288 Header
* h
= (Header
*) ptr
;
290 h
->size
= roundedSize
;
291 h
->marker0
= MARKER0
;
292 h
->marker1
= MARKER1
;
294 ptr
= (void*) ((char*)(h
+1));
296 Trailer
* t
= (Trailer
*) ((char*)ptr
+ roundedSize
);
297 t
->marker2
[0] = MARKER2_0
;
298 t
->marker2
[1] = MARKER2_1
;
300 // Copy old memory into new memory (don't copy too much!)
301 size_t copy
= oldSize
;
302 if (copy
> aSize
) copy
= aSize
;
303 memcpy(ptr
, aOldAddr
, copy
);
305 // Fill any uncopied memory with the overrun pattern
306 size_t fill
= roundedSize
- copy
;
308 memset((char*)ptr
+ copy
, PATTERN_BYTE
, fill
);
311 if (0 == (LIBMALLOC_NOFREE
& gFlags
)) {
315 // Mark the old header so that a verify will fail if the caller
317 oldh
->marker0
= 0xDEADBEEF;
318 oldh
->marker1
= 0xDEADBEEF;
320 // Munge the body of the old allocation so that if the user
321 // still has a live reference they get messed up
322 void* optr
= (void*) ((char*)(oldh
+1));
323 memset(optr
, FREE_PATTERN_BYTE
, oldh
->rawSize
);
326 if (LIBMALLOC_LOG
& gFlags
) {
327 Log(malloc_log_realloc
, ptr
, aSize
, aOldAddr
);
334 SetMallocFlags(u_long aFlags
)
339 if ((-1 == gLogFD
) && ((LIBMALLOC_LOG
|LIBMALLOC_LOG_RC
) & gFlags
)) {
340 gLogFD
= open("malloc-log", O_CREAT
|O_WRONLY
|O_TRUNC
, 0666);
342 gFlags
&= ~LIBMALLOC_LOG
;
343 printf("unable to create malloc-log: %d\n", errno
);
346 if ((gLogFD
>= 0) && (0 == ((LIBMALLOC_LOG
|LIBMALLOC_LOG_RC
) & gFlags
))) {
351 if (LIBMALLOC_CHECK
& gFlags
) {
352 mallopt(M_CHECK_ACTION
, 1);
356 // Try to guarantee that the address map is always dumped
357 atexit(DumpAddressMap
);
362 static int gFirstTime
= 1;
368 char* s
= getenv("LIBMALLOC_LOG");
371 if (LIBMALLOC_LOG
& flags
) {
372 char m1
[] = "dbgmalloc: enabled memory logging\n";
373 write(1, m1
, sizeof(m1
)-1);
375 if (LIBMALLOC_LOG_RC
& flags
) {
376 char m2
[] = "dbgmalloc: enabled refcnt logging\n";
377 write(1, m2
, sizeof(m2
)-1);
379 if (LIBMALLOC_NOFREE
& flags
) {
380 char m3
[] = "dbgmalloc: disabled free\n";
381 write(1, m3
, sizeof(m3
)-1);
384 SetMallocFlags(flags
);
385 s
= getenv("LIBMALLOC_FILL");
387 gFillCount
= atoi(s
);
388 char m4
[] = "dbgmalloc: adding extra memory fill ";
389 write(1, m4
, sizeof(m4
)-1);
390 write(1, s
, strlen(s
));
395 //----------------------------------------------------------------------
398 void* __wrap_malloc(size_t aSize
)
403 return MallocHook(aSize
, malloc_log_malloc
);
406 void* __wrap_realloc(void* aPtr
, size_t aSize
)
411 return ReallocHook(aPtr
, aSize
);
414 void __wrap_free(void* aPtr
)
419 FreeHook(aPtr
, malloc_log_free
);
422 void* __wrap___builtin_new(size_t aSize
)
427 return MallocHook(aSize
, malloc_log_new
);
430 void __wrap___builtin_delete(void* aPtr
)
435 FreeHook(aPtr
, malloc_log_delete
);
438 void* __wrap___builtin_vec_new(size_t aSize
)
443 return MallocHook(aSize
, malloc_log_new
);
446 void __wrap___builtin_vec_delete(void* aPtr
)
451 FreeHook(aPtr
, malloc_log_delete
);
454 void* __wrap_PR_Malloc(size_t aSize
)
459 return MallocHook(aSize
, malloc_log_malloc
);
462 void* __wrap_PR_Calloc(size_t aSize
, size_t aBsize
)
467 size_t size
= aSize
*aBsize
;
468 void* ptr
= MallocHook(size
, malloc_log_malloc
);
470 memset(ptr
, 0, size
);
475 void* __wrap_PR_Realloc(void* aPtr
, size_t aSize
)
480 return ReallocHook(aPtr
, aSize
);
483 void __wrap_PR_Free(void* aPtr
)
488 FreeHook(aPtr
, malloc_log_free
);
492 //----------------------------------------
494 // Strong symbols so that libc references are routed to us
496 void* malloc(size_t aSize
)
501 return MallocHook(aSize
, malloc_log_malloc
);
504 void* realloc(void* aPtr
, size_t aSize
)
509 return ReallocHook(aPtr
, aSize
);
512 void free(void* aPtr
)
517 FreeHook(aPtr
, malloc_log_free
);
520 void* calloc(size_t aSize
, size_t aBsize
)
525 size_t size
= aSize
*aBsize
;
526 void* ptr
= MallocHook(size
, malloc_log_malloc
);
528 memset(ptr
, 0, size
);
533 void cfree(void* ptr
)
538 FreeHook(ptr
, malloc_log_free
);
541 void* memalign(size_t alignment
, size_t size
)
546 void* valloc(size_t size
)
551 void* pvalloc(size_t size
)
556 void* __builtin_new(size_t aSize
)
561 return MallocHook(aSize
, malloc_log_new
);
564 void __builtin_delete(void* aPtr
)
569 FreeHook(aPtr
, malloc_log_delete
);
572 void* __builtin_vec_new(size_t aSize
)
577 return MallocHook(aSize
, malloc_log_new
);
580 void __builtin_vec_delete(void* aPtr
)
585 FreeHook(aPtr
, malloc_log_delete
);
589 __log_addref(void* p
, int oldrc
, int newrc
)
594 if (LIBMALLOC_LOG_RC
& gFlags
) {
595 Log(malloc_log_addref
, p
, size_t(oldrc
), (void*)newrc
);
600 __log_release(void* p
, int oldrc
, int newrc
)
605 if (LIBMALLOC_LOG_RC
& gFlags
) {
606 Log(malloc_log_release
, p
, size_t(oldrc
), (void*)newrc
);