blob: b21bc6acf56132e5d090e7dc5fedbe21a5321ba4 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28#include <errno.h>
29#include <pthread.h>
30#include <stdio.h>
31#include <arpa/inet.h>
32#include <sys/socket.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36#include <errno.h>
37#include <stddef.h>
38#include <stdarg.h>
39#include <fcntl.h>
40#include <unwind.h>
41
42#include <sys/socket.h>
43#include <sys/un.h>
44#include <sys/select.h>
45#include <sys/types.h>
46#include <sys/system_properties.h>
47
48#include "dlmalloc.h"
49#include "logd.h"
50
51// =============================================================================
52// Utilities directly used by Dalvik
53// =============================================================================
54
55#define HASHTABLE_SIZE 1543
56#define BACKTRACE_SIZE 32
57/* flag definitions, currently sharing storage with "size" */
58#define SIZE_FLAG_ZYGOTE_CHILD (1<<31)
59#define SIZE_FLAG_MASK (SIZE_FLAG_ZYGOTE_CHILD)
60
61#define MAX_SIZE_T (~(size_t)0)
62
63/*
64 * In a VM process, this is set to 1 after fork()ing out of zygote.
65 */
66int gMallocLeakZygoteChild = 0;
67
68// =============================================================================
69// Structures
70// =============================================================================
71
72typedef struct HashEntry HashEntry;
73struct HashEntry {
74 size_t slot;
75 HashEntry* prev;
76 HashEntry* next;
77 size_t numEntries;
78 // fields above "size" are NOT sent to the host
79 size_t size;
80 size_t allocations;
81 intptr_t backtrace[0];
82};
83
84typedef struct HashTable HashTable;
85struct HashTable {
86 size_t count;
87 HashEntry* slots[HASHTABLE_SIZE];
88};
89
90static pthread_mutex_t gAllocationsMutex = PTHREAD_MUTEX_INITIALIZER;
91static HashTable gHashTable;
92
93// =============================================================================
Andy McFadden39f37452009-07-21 15:25:23 -070094// log functions
95// =============================================================================
96
97#define debug_log(format, ...) \
98 __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_leak", (format), ##__VA_ARGS__ )
99
100// =============================================================================
101// output functions
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800102// =============================================================================
103
104static int hash_entry_compare(const void* arg1, const void* arg2)
105{
106 HashEntry* e1 = *(HashEntry**)arg1;
107 HashEntry* e2 = *(HashEntry**)arg2;
108
109 size_t nbAlloc1 = e1->allocations;
110 size_t nbAlloc2 = e2->allocations;
111 size_t size1 = e1->size & ~SIZE_FLAG_MASK;
112 size_t size2 = e2->size & ~SIZE_FLAG_MASK;
113 size_t alloc1 = nbAlloc1 * size1;
114 size_t alloc2 = nbAlloc2 * size2;
115
116 // sort in descending order by:
117 // 1) total size
118 // 2) number of allocations
119 //
120 // This is used for sorting, not determination of equality, so we don't
121 // need to compare the bit flags.
122 int result;
123 if (alloc1 > alloc2) {
124 result = -1;
125 } else if (alloc1 < alloc2) {
126 result = 1;
127 } else {
128 if (nbAlloc1 > nbAlloc2) {
129 result = -1;
130 } else if (nbAlloc1 < nbAlloc2) {
131 result = 1;
132 } else {
133 result = 0;
134 }
135 }
136 return result;
137}
138
139/*
140 * Retrieve native heap information.
141 *
142 * "*info" is set to a buffer we allocate
143 * "*overallSize" is set to the size of the "info" buffer
144 * "*infoSize" is set to the size of a single entry
145 * "*totalMemory" is set to the sum of all allocations we're tracking; does
146 * not include heap overhead
147 * "*backtraceSize" is set to the maximum number of entries in the back trace
148 */
149void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
150 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize)
151{
152 // don't do anything if we have invalid arguments
153 if (info == NULL || overallSize == NULL || infoSize == NULL ||
154 totalMemory == NULL || backtraceSize == NULL) {
155 return;
156 }
157
158 pthread_mutex_lock(&gAllocationsMutex);
159
160 if (gHashTable.count == 0) {
161 *info = NULL;
162 *overallSize = 0;
163 *infoSize = 0;
164 *totalMemory = 0;
165 *backtraceSize = 0;
166 goto done;
167 }
168
169 void** list = (void**)dlmalloc(sizeof(void*) * gHashTable.count);
170
171 // debug_log("*****\ngHashTable.count = %d\n", gHashTable.count);
172 // debug_log("list = %p\n", list);
173
174 // get the entries into an array to be sorted
175 int index = 0;
176 int i;
177 for (i = 0 ; i < HASHTABLE_SIZE ; i++) {
178 HashEntry* entry = gHashTable.slots[i];
179 while (entry != NULL) {
180 list[index] = entry;
181 *totalMemory = *totalMemory +
182 ((entry->size & ~SIZE_FLAG_MASK) * entry->allocations);
183 index++;
184 entry = entry->next;
185 }
186 }
187
188 // debug_log("sorted list!\n");
189 // XXX: the protocol doesn't allow variable size for the stack trace (yet)
190 *infoSize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * BACKTRACE_SIZE);
191 *overallSize = *infoSize * gHashTable.count;
192 *backtraceSize = BACKTRACE_SIZE;
193
194 // debug_log("infoSize = 0x%x overall = 0x%x\n", *infoSize, *overallSize);
195 // now get A byte array big enough for this
196 *info = (uint8_t*)dlmalloc(*overallSize);
197
198 // debug_log("info = %p\n", info);
199 if (*info == NULL) {
200 *overallSize = 0;
André Goddard Rosa350bb352010-02-05 16:01:05 -0200201 goto out_nomem_info;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800202 }
203
204 // debug_log("sorting list...\n");
205 qsort((void*)list, gHashTable.count, sizeof(void*), hash_entry_compare);
206
207 uint8_t* head = *info;
208 const int count = gHashTable.count;
209 for (i = 0 ; i < count ; i++) {
210 HashEntry* entry = list[i];
211 size_t entrySize = (sizeof(size_t) * 2) + (sizeof(intptr_t) * entry->numEntries);
212 if (entrySize < *infoSize) {
213 /* we're writing less than a full entry, clear out the rest */
André Goddard Rosa3f612122010-03-28 21:32:36 -0300214 memset(head + entrySize, 0, *infoSize - entrySize);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800215 } else {
216 /* make sure the amount we're copying doesn't exceed the limit */
217 entrySize = *infoSize;
218 }
219 memcpy(head, &(entry->size), entrySize);
220 head += *infoSize;
221 }
222
André Goddard Rosa350bb352010-02-05 16:01:05 -0200223out_nomem_info:
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800224 dlfree(list);
225
226done:
227 // debug_log("+++++ done!\n");
228 pthread_mutex_unlock(&gAllocationsMutex);
229}
230
231void free_malloc_leak_info(uint8_t* info)
232{
233 dlfree(info);
234}
235
236struct mallinfo mallinfo()
237{
238 return dlmallinfo();
239}
240
241void* valloc(size_t bytes) {
242 /* assume page size of 4096 bytes */
243 return memalign( getpagesize(), bytes );
244}
245
246
247/*
248 * Code guarded by MALLOC_LEAK_CHECK is only needed when malloc check is
249 * enabled. Currently we exclude them in libc.so, and only include them in
250 * libc_debug.so.
251 */
252#ifdef MALLOC_LEAK_CHECK
253#define MALLOC_ALIGNMENT 8
254#define GUARD 0x48151642
255
256#define DEBUG 0
257
258// =============================================================================
259// Structures
260// =============================================================================
261typedef struct AllocationEntry AllocationEntry;
262struct AllocationEntry {
263 HashEntry* entry;
264 uint32_t guard;
265};
266
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800267
268// =============================================================================
269// Hash Table functions
270// =============================================================================
271static uint32_t get_hash(intptr_t* backtrace, size_t numEntries)
272{
273 if (backtrace == NULL) return 0;
274
275 int hash = 0;
276 size_t i;
277 for (i = 0 ; i < numEntries ; i++) {
278 hash = (hash * 33) + (backtrace[i] >> 2);
279 }
280
281 return hash;
282}
283
284static HashEntry* find_entry(HashTable* table, int slot,
285 intptr_t* backtrace, size_t numEntries, size_t size)
286{
287 HashEntry* entry = table->slots[slot];
288 while (entry != NULL) {
289 //debug_log("backtrace: %p, entry: %p entry->backtrace: %p\n",
290 // backtrace, entry, (entry != NULL) ? entry->backtrace : NULL);
291 /*
292 * See if the entry matches exactly. We compare the "size" field,
293 * including the flag bits.
294 */
295 if (entry->size == size && entry->numEntries == numEntries &&
296 !memcmp(backtrace, entry->backtrace, numEntries * sizeof(intptr_t))) {
297 return entry;
298 }
299
300 entry = entry->next;
301 }
302
303 return NULL;
304}
305
306static HashEntry* record_backtrace(intptr_t* backtrace, size_t numEntries, size_t size)
307{
308 size_t hash = get_hash(backtrace, numEntries);
309 size_t slot = hash % HASHTABLE_SIZE;
310
311 if (size & SIZE_FLAG_MASK) {
312 debug_log("malloc_debug: allocation %zx exceeds bit width\n", size);
313 abort();
314 }
315
316 if (gMallocLeakZygoteChild)
317 size |= SIZE_FLAG_ZYGOTE_CHILD;
318
319 HashEntry* entry = find_entry(&gHashTable, slot, backtrace, numEntries, size);
320
321 if (entry != NULL) {
322 entry->allocations++;
323 } else {
324 // create a new entry
325 entry = (HashEntry*)dlmalloc(sizeof(HashEntry) + numEntries*sizeof(intptr_t));
André Goddard Rosa5751c542010-02-05 16:03:09 -0200326 if (!entry)
327 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800328 entry->allocations = 1;
329 entry->slot = slot;
330 entry->prev = NULL;
331 entry->next = gHashTable.slots[slot];
332 entry->numEntries = numEntries;
333 entry->size = size;
334
335 memcpy(entry->backtrace, backtrace, numEntries * sizeof(intptr_t));
336
337 gHashTable.slots[slot] = entry;
338
339 if (entry->next != NULL) {
340 entry->next->prev = entry;
341 }
342
343 // we just added an entry, increase the size of the hashtable
344 gHashTable.count++;
345 }
346
347 return entry;
348}
349
350static int is_valid_entry(HashEntry* entry)
351{
352 if (entry != NULL) {
353 int i;
354 for (i = 0 ; i < HASHTABLE_SIZE ; i++) {
355 HashEntry* e1 = gHashTable.slots[i];
356
357 while (e1 != NULL) {
358 if (e1 == entry) {
359 return 1;
360 }
361
362 e1 = e1->next;
363 }
364 }
365 }
366
367 return 0;
368}
369
370static void remove_entry(HashEntry* entry)
371{
372 HashEntry* prev = entry->prev;
373 HashEntry* next = entry->next;
374
375 if (prev != NULL) entry->prev->next = next;
376 if (next != NULL) entry->next->prev = prev;
377
378 if (prev == NULL) {
379 // we are the head of the list. set the head to be next
380 gHashTable.slots[entry->slot] = entry->next;
381 }
382
383 // we just removed and entry, decrease the size of the hashtable
384 gHashTable.count--;
385}
386
387
388// =============================================================================
389// stack trace functions
390// =============================================================================
391
392typedef struct
393{
394 size_t count;
395 intptr_t* addrs;
396} stack_crawl_state_t;
397
398
399/* depends how the system includes define this */
400#ifdef HAVE_UNWIND_CONTEXT_STRUCT
401typedef struct _Unwind_Context __unwind_context;
402#else
403typedef _Unwind_Context __unwind_context;
404#endif
405
406static _Unwind_Reason_Code trace_function(__unwind_context *context, void *arg)
407{
408 stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
409 if (state->count) {
410 intptr_t ip = (intptr_t)_Unwind_GetIP(context);
411 if (ip) {
412 state->addrs[0] = ip;
413 state->addrs++;
414 state->count--;
415 return _URC_NO_REASON;
416 }
417 }
418 /*
419 * If we run out of space to record the address or 0 has been seen, stop
420 * unwinding the stack.
421 */
422 return _URC_END_OF_STACK;
423}
424
425static inline
426int get_backtrace(intptr_t* addrs, size_t max_entries)
427{
428 stack_crawl_state_t state;
429 state.count = max_entries;
430 state.addrs = (intptr_t*)addrs;
431 _Unwind_Backtrace(trace_function, (void*)&state);
432 return max_entries - state.count;
433}
434
435// =============================================================================
436// malloc leak function dispatcher
437// =============================================================================
438
439static void* leak_malloc(size_t bytes);
440static void leak_free(void* mem);
441static void* leak_calloc(size_t n_elements, size_t elem_size);
442static void* leak_realloc(void* oldMem, size_t bytes);
443static void* leak_memalign(size_t alignment, size_t bytes);
444
445static void* fill_malloc(size_t bytes);
446static void fill_free(void* mem);
447static void* fill_realloc(void* oldMem, size_t bytes);
448static void* fill_memalign(size_t alignment, size_t bytes);
449
450static void* chk_malloc(size_t bytes);
451static void chk_free(void* mem);
452static void* chk_calloc(size_t n_elements, size_t elem_size);
453static void* chk_realloc(void* oldMem, size_t bytes);
454static void* chk_memalign(size_t alignment, size_t bytes);
455
456typedef struct {
457 void* (*malloc)(size_t bytes);
458 void (*free)(void* mem);
459 void* (*calloc)(size_t n_elements, size_t elem_size);
460 void* (*realloc)(void* oldMem, size_t bytes);
461 void* (*memalign)(size_t alignment, size_t bytes);
462} MallocDebug;
463
464static const MallocDebug gMallocEngineTable[] __attribute__((aligned(32))) =
465{
466 { dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign },
467 { leak_malloc, leak_free, leak_calloc, leak_realloc, leak_memalign },
468 { fill_malloc, fill_free, dlcalloc, fill_realloc, fill_memalign },
469 { chk_malloc, chk_free, chk_calloc, chk_realloc, chk_memalign }
470};
471
472enum {
473 INDEX_NORMAL = 0,
474 INDEX_LEAK_CHECK,
475 INDEX_MALLOC_FILL,
476 INDEX_MALLOC_CHECK,
477};
478
479static MallocDebug const * gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL];
480static int gMallocDebugLevel;
481static int gTrapOnError = 1;
482
483void* malloc(size_t bytes) {
484 return gMallocDispatch->malloc(bytes);
485}
486void free(void* mem) {
487 gMallocDispatch->free(mem);
488}
489void* calloc(size_t n_elements, size_t elem_size) {
490 return gMallocDispatch->calloc(n_elements, elem_size);
491}
492void* realloc(void* oldMem, size_t bytes) {
493 return gMallocDispatch->realloc(oldMem, bytes);
494}
495void* memalign(size_t alignment, size_t bytes) {
496 return gMallocDispatch->memalign(alignment, bytes);
497}
498
499// =============================================================================
500// malloc check functions
501// =============================================================================
502
503#define CHK_FILL_FREE 0xef
504#define CHK_SENTINEL_VALUE 0xeb
505#define CHK_SENTINEL_HEAD_SIZE 16
506#define CHK_SENTINEL_TAIL_SIZE 16
507#define CHK_OVERHEAD_SIZE ( CHK_SENTINEL_HEAD_SIZE + \
508 CHK_SENTINEL_TAIL_SIZE + \
509 sizeof(size_t) )
510
511static void dump_stack_trace()
512{
513 intptr_t addrs[20];
514 int c = get_backtrace(addrs, 20);
515 char buf[16];
516 char tmp[16*20];
517 int i;
518
519 tmp[0] = 0; // Need to initialize tmp[0] for the first strcat
520 for (i=0 ; i<c; i++) {
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200521 snprintf(buf, sizeof buf, "%2d: %08x\n", i, addrs[i]);
522 strlcat(tmp, buf, sizeof tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800523 }
524 __libc_android_log_print(ANDROID_LOG_ERROR, "libc", "call stack:\n%s", tmp);
525}
526
527static int is_valid_malloc_pointer(void* addr)
528{
529 return 1;
530}
531
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200532static void assert_log_message(const char* format, ...)
533{
534 va_list args;
535
536 pthread_mutex_lock(&gAllocationsMutex);
537 gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL];
538 va_start(args, format);
539 __libc_android_log_vprint(ANDROID_LOG_ERROR, "libc",
540 format, args);
541 va_end(args);
542 dump_stack_trace();
543 if (gTrapOnError) {
544 __builtin_trap();
545 }
546 gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_CHECK];
547 pthread_mutex_unlock(&gAllocationsMutex);
548}
549
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800550static void assert_valid_malloc_pointer(void* mem)
551{
552 if (mem && !is_valid_malloc_pointer(mem)) {
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200553 assert_log_message(
554 "*** MALLOC CHECK: buffer %p, is not a valid "
555 "malloc pointer (are you mixing up new/delete "
556 "and malloc/free?)", mem);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800557 }
558}
559
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200560/* Check that a given address corresponds to a guarded block,
561 * and returns its original allocation size in '*allocated'.
562 * 'func' is the capitalized name of the caller function.
563 * Returns 0 on success, or -1 on failure.
564 * NOTE: Does not return if gTrapOnError is set.
565 */
566static int chk_mem_check(void* mem,
567 size_t* allocated,
568 const char* func)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800569{
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200570 char* buffer;
571 size_t offset, bytes;
572 int i;
573 char* buf;
574
575 /* first check the bytes in the sentinel header */
576 buf = (char*)mem - CHK_SENTINEL_HEAD_SIZE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800577 for (i=0 ; i<CHK_SENTINEL_HEAD_SIZE ; i++) {
578 if (buf[i] != CHK_SENTINEL_VALUE) {
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200579 assert_log_message(
580 "*** %s CHECK: buffer %p "
581 "corrupted %d bytes before allocation",
582 func, mem, CHK_SENTINEL_HEAD_SIZE-i);
583 return -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800584 }
585 }
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200586
587 /* then the ones in the sentinel trailer */
588 buffer = (char*)mem - CHK_SENTINEL_HEAD_SIZE;
589 offset = dlmalloc_usable_size(buffer) - sizeof(size_t);
590 bytes = *(size_t *)(buffer + offset);
591
592 buf = (char*)mem + bytes;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800593 for (i=CHK_SENTINEL_TAIL_SIZE-1 ; i>=0 ; i--) {
594 if (buf[i] != CHK_SENTINEL_VALUE) {
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200595 assert_log_message(
596 "*** %s CHECK: buffer %p, size=%lu, "
597 "corrupted %d bytes after allocation",
598 func, buffer, bytes, i+1);
599 return -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800600 }
601 }
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200602
603 *allocated = bytes;
604 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800605}
606
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200607
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800608void* chk_malloc(size_t bytes)
609{
610 char* buffer = (char*)dlmalloc(bytes + CHK_OVERHEAD_SIZE);
611 if (buffer) {
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200612 memset(buffer, CHK_SENTINEL_VALUE, bytes + CHK_OVERHEAD_SIZE);
613 size_t offset = dlmalloc_usable_size(buffer) - sizeof(size_t);
614 *(size_t *)(buffer + offset) = bytes;
615 buffer += CHK_SENTINEL_HEAD_SIZE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800616 }
617 return buffer;
618}
619
620void chk_free(void* mem)
621{
622 assert_valid_malloc_pointer(mem);
623 if (mem) {
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200624 size_t size;
625 char* buffer;
626
627 if (chk_mem_check(mem, &size, "FREE") == 0) {
628 buffer = (char*)mem - CHK_SENTINEL_HEAD_SIZE;
629 memset(buffer, CHK_FILL_FREE, size + CHK_OVERHEAD_SIZE);
630 dlfree(buffer);
631 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800632 }
633}
634
635void* chk_calloc(size_t n_elements, size_t elem_size)
636{
637 size_t size;
638 void* ptr;
639
640 /* Fail on overflow - just to be safe even though this code runs only
641 * within the debugging C library, not the production one */
642 if (n_elements && MAX_SIZE_T / n_elements < elem_size) {
643 return NULL;
644 }
645 size = n_elements * elem_size;
646 ptr = chk_malloc(size);
647 if (ptr != NULL) {
648 memset(ptr, 0, size);
649 }
650 return ptr;
651}
652
653void* chk_realloc(void* mem, size_t bytes)
654{
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200655 char* buffer;
656 int ret;
657 size_t old_bytes = 0;
658
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800659 assert_valid_malloc_pointer(mem);
David 'Digit' Turnerc4eee372009-07-08 14:22:41 +0200660
661 if (mem != NULL && chk_mem_check(mem, &old_bytes, "REALLOC") < 0)
662 return NULL;
663
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800664 char* new_buffer = chk_malloc(bytes);
665 if (mem == NULL) {
666 return new_buffer;
667 }
668
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800669 if (new_buffer) {
André Goddard Rosa291100c2010-02-05 16:32:56 -0200670 if (bytes > old_bytes)
671 bytes = old_bytes;
672 memcpy(new_buffer, mem, bytes);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800673 chk_free(mem);
674 }
675
676 return new_buffer;
677}
678
679void* chk_memalign(size_t alignment, size_t bytes)
680{
681 // XXX: it's better to use malloc, than being wrong
682 return chk_malloc(bytes);
683}
684
685// =============================================================================
686// malloc fill functions
687// =============================================================================
688
689void* fill_malloc(size_t bytes)
690{
691 void* buffer = dlmalloc(bytes);
692 if (buffer) {
693 memset(buffer, CHK_SENTINEL_VALUE, bytes);
694 }
695 return buffer;
696}
697
698void fill_free(void* mem)
699{
700 size_t bytes = dlmalloc_usable_size(mem);
701 memset(mem, CHK_FILL_FREE, bytes);
702 dlfree(mem);
703}
704
705void* fill_realloc(void* mem, size_t bytes)
706{
707 void* buffer = fill_malloc(bytes);
708 if (mem == NULL) {
709 return buffer;
710 }
711 if (buffer) {
712 size_t old_size = dlmalloc_usable_size(mem);
713 size_t size = (bytes < old_size)?(bytes):(old_size);
714 memcpy(buffer, mem, size);
715 fill_free(mem);
716 }
717 return buffer;
718}
719
720void* fill_memalign(size_t alignment, size_t bytes)
721{
722 void* buffer = dlmemalign(alignment, bytes);
723 if (buffer) {
724 memset(buffer, CHK_SENTINEL_VALUE, bytes);
725 }
726 return buffer;
727}
728
729// =============================================================================
730// malloc leak functions
731// =============================================================================
732
733#define MEMALIGN_GUARD ((void*)0xA1A41520)
734
735void* leak_malloc(size_t bytes)
736{
737 // allocate enough space infront of the allocation to store the pointer for
738 // the alloc structure. This will making free'ing the structer really fast!
739
740 // 1. allocate enough memory and include our header
741 // 2. set the base pointer to be right after our header
742
743 void* base = dlmalloc(bytes + sizeof(AllocationEntry));
744 if (base != NULL) {
745 pthread_mutex_lock(&gAllocationsMutex);
746
747 intptr_t backtrace[BACKTRACE_SIZE];
748 size_t numEntries = get_backtrace(backtrace, BACKTRACE_SIZE);
749
750 AllocationEntry* header = (AllocationEntry*)base;
751 header->entry = record_backtrace(backtrace, numEntries, bytes);
752 header->guard = GUARD;
753
754 // now increment base to point to after our header.
755 // this should just work since our header is 8 bytes.
756 base = (AllocationEntry*)base + 1;
757
758 pthread_mutex_unlock(&gAllocationsMutex);
759 }
760
761 return base;
762}
763
764void leak_free(void* mem)
765{
766 if (mem != NULL) {
767 pthread_mutex_lock(&gAllocationsMutex);
768
769 // check the guard to make sure it is valid
770 AllocationEntry* header = (AllocationEntry*)mem - 1;
771
772 if (header->guard != GUARD) {
773 // could be a memaligned block
774 if (((void**)mem)[-1] == MEMALIGN_GUARD) {
775 mem = ((void**)mem)[-2];
776 header = (AllocationEntry*)mem - 1;
777 }
778 }
779
780 if (header->guard == GUARD || is_valid_entry(header->entry)) {
781 // decrement the allocations
782 HashEntry* entry = header->entry;
783 entry->allocations--;
784 if (entry->allocations <= 0) {
785 remove_entry(entry);
786 dlfree(entry);
787 }
788
789 // now free the memory!
790 dlfree(header);
791 } else {
792 debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
793 header->guard, header->entry);
794 }
795
796 pthread_mutex_unlock(&gAllocationsMutex);
797 }
798}
799
800void* leak_calloc(size_t n_elements, size_t elem_size)
801{
802 size_t size;
803 void* ptr;
804
805 /* Fail on overflow - just to be safe even though this code runs only
806 * within the debugging C library, not the production one */
807 if (n_elements && MAX_SIZE_T / n_elements < elem_size) {
808 return NULL;
809 }
810 size = n_elements * elem_size;
811 ptr = leak_malloc(size);
812 if (ptr != NULL) {
813 memset(ptr, 0, size);
814 }
815 return ptr;
816}
817
818void* leak_realloc(void* oldMem, size_t bytes)
819{
820 if (oldMem == NULL) {
821 return leak_malloc(bytes);
822 }
823 void* newMem = NULL;
824 AllocationEntry* header = (AllocationEntry*)oldMem - 1;
825 if (header && header->guard == GUARD) {
826 size_t oldSize = header->entry->size & ~SIZE_FLAG_MASK;
827 newMem = leak_malloc(bytes);
828 if (newMem != NULL) {
829 size_t copySize = (oldSize <= bytes) ? oldSize : bytes;
830 memcpy(newMem, oldMem, copySize);
831 leak_free(oldMem);
832 }
833 } else {
834 newMem = dlrealloc(oldMem, bytes);
835 }
836 return newMem;
837}
838
839void* leak_memalign(size_t alignment, size_t bytes)
840{
841 // we can just use malloc
842 if (alignment <= MALLOC_ALIGNMENT)
843 return leak_malloc(bytes);
844
845 // need to make sure it's a power of two
846 if (alignment & (alignment-1))
847 alignment = 1L << (31 - __builtin_clz(alignment));
848
849 // here, aligment is at least MALLOC_ALIGNMENT<<1 bytes
850 // we will align by at least MALLOC_ALIGNMENT bytes
851 // and at most alignment-MALLOC_ALIGNMENT bytes
852 size_t size = (alignment-MALLOC_ALIGNMENT) + bytes;
853 void* base = leak_malloc(size);
854 if (base != NULL) {
855 intptr_t ptr = (intptr_t)base;
856 if ((ptr % alignment) == 0)
857 return base;
858
859 // align the pointer
860 ptr += ((-ptr) % alignment);
861
862 // there is always enough space for the base pointer and the guard
863 ((void**)ptr)[-1] = MEMALIGN_GUARD;
864 ((void**)ptr)[-2] = base;
865
866 return (void*)ptr;
867 }
868 return base;
869}
870#endif /* MALLOC_LEAK_CHECK */
871
872// called from libc_init()
873extern char* __progname;
874
875void malloc_debug_init()
876{
877 unsigned int level = 0;
878#ifdef MALLOC_LEAK_CHECK
879 // if MALLOC_LEAK_CHECK is enabled, use level=1 by default
880 level = 1;
881#endif
882 char env[PROP_VALUE_MAX];
883 int len = __system_property_get("libc.debug.malloc", env);
884
885 if (len) {
886 level = atoi(env);
887#ifndef MALLOC_LEAK_CHECK
888 /* Alert the user that libc_debug.so needs to be installed as libc.so
889 * when performing malloc checks.
890 */
891 if (level != 0) {
892 __libc_android_log_print(ANDROID_LOG_INFO, "libc",
893 "Malloc checks need libc_debug.so pushed to the device!\n");
894
895 }
896#endif
897 }
898
899#ifdef MALLOC_LEAK_CHECK
900 gMallocDebugLevel = level;
901 switch (level) {
902 default:
903 case 0:
904 gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL];
905 break;
906 case 1:
907 __libc_android_log_print(ANDROID_LOG_INFO, "libc",
908 "%s using MALLOC_DEBUG = %d (leak checker)\n",
909 __progname, level);
910 gMallocDispatch = &gMallocEngineTable[INDEX_LEAK_CHECK];
911 break;
912 case 5:
913 __libc_android_log_print(ANDROID_LOG_INFO, "libc",
914 "%s using MALLOC_DEBUG = %d (fill)\n",
915 __progname, level);
916 gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_FILL];
917 break;
918 case 10:
919 __libc_android_log_print(ANDROID_LOG_INFO, "libc",
920 "%s using MALLOC_DEBUG = %d (sentinels, fill)\n",
921 __progname, level);
922 gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_CHECK];
923 break;
924 }
925#endif
926}