blob: 85629001ff8d1010fd2e3c74d49f6829873011b2 [file] [log] [blame]
Christopher Ferris63860cb2015-11-16 17:30:32 -08001/*
2 * Copyright (C) 2012 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
29#include <errno.h>
30#include <inttypes.h>
31#include <malloc.h>
32#include <string.h>
33#include <sys/cdefs.h>
34#include <sys/param.h>
35#include <unistd.h>
36
37#include <vector>
38
39#include <private/bionic_malloc_dispatch.h>
40
41#include "backtrace.h"
42#include "DebugData.h"
43#include "debug_disable.h"
44#include "debug_log.h"
45#include "malloc_debug.h"
46
47// ------------------------------------------------------------------------
48// Global Data
49// ------------------------------------------------------------------------
50DebugData* g_debug;
51
52int* g_malloc_zygote_child;
53
54const MallocDispatch* g_dispatch;
55// ------------------------------------------------------------------------
56
57// ------------------------------------------------------------------------
58// Use C style prototypes for all exported functions. This makes it easy
59// to do dlsym lookups during libc initialization when malloc debug
60// is enabled.
61// ------------------------------------------------------------------------
62__BEGIN_DECLS
63
64bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child);
65void debug_finalize();
66void debug_get_malloc_leak_info(
67 uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
68 size_t* backtrace_size);
69void debug_free_malloc_leak_info(uint8_t* info);
70size_t debug_malloc_usable_size(void* pointer);
71void* debug_malloc(size_t size);
72void debug_free(void* pointer);
73void* debug_memalign(size_t alignment, size_t bytes);
74void* debug_realloc(void* pointer, size_t bytes);
75void* debug_calloc(size_t nmemb, size_t bytes);
76struct mallinfo debug_mallinfo();
77int debug_posix_memalign(void** memptr, size_t alignment, size_t size);
78
79#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
80void* debug_pvalloc(size_t bytes);
81void* debug_valloc(size_t size);
82#endif
83
84__END_DECLS
85// ------------------------------------------------------------------------
86
Colin Cross7a28a3c2016-02-07 22:51:15 -080087static void InitAtfork() {
88 static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
89 pthread_once(&atfork_init, [](){
90 pthread_atfork(
91 [](){
92 if (g_debug != nullptr) {
93 g_debug->PrepareFork();
94 }
95 },
96 [](){
97 if (g_debug != nullptr) {
98 g_debug->PostForkParent();
99 }
100 },
101 [](){
102 if (g_debug != nullptr) {
103 g_debug->PostForkChild();
104 }
105 }
106 );
107 });
108}
Christopher Ferris63860cb2015-11-16 17:30:32 -0800109static void LogTagError(const Header* header, const void* pointer, const char* name) {
110 ScopedDisableDebugCalls disable;
111
112 error_log(LOG_DIVIDER);
Christopher Ferris7993b802016-01-28 18:35:05 -0800113 if (header->tag == DEBUG_FREE_TAG) {
114 error_log("+++ ALLOCATION %p USED AFTER FREE (%s)", pointer, name);
115 if (g_debug->config().options & FREE_TRACK) {
116 g_debug->free_track->LogBacktrace(header);
117 }
118 } else {
119 error_log("+++ ALLOCATION %p HAS INVALID TAG %" PRIx32 " (%s)", pointer, header->tag, name);
120 }
Christopher Ferris63860cb2015-11-16 17:30:32 -0800121 error_log("Backtrace at time of failure:");
122 std::vector<uintptr_t> frames(64);
123 size_t frame_num = backtrace_get(frames.data(), frames.size());
124 frames.resize(frame_num);
125 backtrace_log(frames.data(), frames.size());
126 error_log(LOG_DIVIDER);
127}
128
129static void* InitHeader(Header* header, void* orig_pointer, size_t size) {
130 header->tag = DEBUG_TAG;
131 header->orig_pointer = orig_pointer;
132 header->size = size;
133 if (*g_malloc_zygote_child) {
134 header->set_zygote();
135 }
136 header->usable_size = g_dispatch->malloc_usable_size(orig_pointer);
137 if (header->usable_size == 0) {
138 g_dispatch->free(orig_pointer);
139 return nullptr;
140 }
141 header->usable_size -= g_debug->pointer_offset() +
142 reinterpret_cast<uintptr_t>(orig_pointer) - reinterpret_cast<uintptr_t>(header);
143
144 if (g_debug->config().options & FRONT_GUARD) {
145 uint8_t* guard = g_debug->GetFrontGuard(header);
146 memset(guard, g_debug->config().front_guard_value, g_debug->config().front_guard_bytes);
147 }
148
149 if (g_debug->config().options & REAR_GUARD) {
150 uint8_t* guard = g_debug->GetRearGuard(header);
151 memset(guard, g_debug->config().rear_guard_value, g_debug->config().rear_guard_bytes);
152 // If the rear guard is enabled, set the usable size to the exact size
153 // of the allocation.
154 header->usable_size = header->real_size();
155 }
156
157 bool backtrace_found = false;
158 if (g_debug->config().options & BACKTRACE) {
159 BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
160 if (g_debug->backtrace->enabled()) {
Christopher Ferris7993b802016-01-28 18:35:05 -0800161 back_header->num_frames = backtrace_get(
162 &back_header->frames[0], g_debug->config().backtrace_frames);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800163 backtrace_found = back_header->num_frames > 0;
164 } else {
165 back_header->num_frames = 0;
166 }
Christopher Ferris63860cb2015-11-16 17:30:32 -0800167 }
168
169 if (g_debug->config().options & TRACK_ALLOCS) {
170 g_debug->track->Add(header, backtrace_found);
171 }
172
173 return g_debug->GetPointer(header);
174}
175
176bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child) {
177 if (malloc_zygote_child == nullptr) {
178 return false;
179 }
Colin Cross7a28a3c2016-02-07 22:51:15 -0800180
181 InitAtfork();
182
Christopher Ferris63860cb2015-11-16 17:30:32 -0800183 g_malloc_zygote_child = malloc_zygote_child;
184
185 g_dispatch = malloc_dispatch;
186
187 if (!DebugDisableInitialize()) {
188 return false;
189 }
190
191 DebugData* debug = new DebugData();
192 if (!debug->Initialize()) {
193 delete debug;
194 DebugDisableFinalize();
195 return false;
196 }
197 g_debug = debug;
198
199 // Always enable the backtrace code since we will use it in a number
200 // of different error cases.
201 backtrace_startup();
202
203 return true;
204}
205
206void debug_finalize() {
207 if (g_debug == nullptr) {
208 return;
209 }
210
211 if (g_debug->config().options & FREE_TRACK) {
212 g_debug->free_track->VerifyAll(*g_debug);
213 }
214
215 if (g_debug->config().options & LEAK_TRACK) {
216 g_debug->track->DisplayLeaks(*g_debug);
217 }
218
219 backtrace_shutdown();
220
221 DebugDisableSet(true);
222
223 delete g_debug;
224 g_debug = nullptr;
225
226 DebugDisableFinalize();
227}
228
229void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size,
230 size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
231 ScopedDisableDebugCalls disable;
232
233 // Verify the arguments.
234 if (info == nullptr || overall_size == nullptr || info_size == NULL ||
235 total_memory == nullptr || backtrace_size == nullptr) {
236 error_log("get_malloc_leak_info: At least one invalid parameter.");
237 return;
238 }
239
240 *info = nullptr;
241 *overall_size = 0;
242 *info_size = 0;
243 *total_memory = 0;
244 *backtrace_size = 0;
245
246 if (!(g_debug->config().options & BACKTRACE)) {
247 error_log("get_malloc_leak_info: Allocations not being tracked, to enable "
248 "set the option 'backtrace'.");
249 return;
250 }
251
252 g_debug->track->GetInfo(*g_debug, info, overall_size, info_size, total_memory, backtrace_size);
253}
254
255void debug_free_malloc_leak_info(uint8_t* info) {
256 g_dispatch->free(info);
257}
258
259size_t debug_malloc_usable_size(void* pointer) {
260 if (DebugCallsDisabled() || !g_debug->need_header() || pointer == nullptr) {
261 return g_dispatch->malloc_usable_size(pointer);
262 }
263
264 Header* header = g_debug->GetHeader(pointer);
265 if (header->tag != DEBUG_TAG) {
266 LogTagError(header, pointer, "malloc_usable_size");
267 return 0;
268 }
269
270 return header->usable_size;
271}
272
273void* debug_malloc(size_t size) {
274 if (DebugCallsDisabled()) {
275 return g_dispatch->malloc(size);
276 }
277
278 size_t real_size = size + g_debug->extra_bytes();
279 if (real_size < size) {
280 // Overflow.
281 errno = ENOMEM;
282 return nullptr;
283 }
284
285 void* pointer;
286 if (g_debug->need_header()) {
287 if (size > Header::max_size()) {
288 errno = ENOMEM;
289 return nullptr;
290 }
291
292 Header* header = reinterpret_cast<Header*>(g_dispatch->memalign(sizeof(uintptr_t), real_size));
293 if (header == nullptr) {
294 return nullptr;
295 }
296 pointer = InitHeader(header, header, size);
297 } else {
298 pointer = g_dispatch->malloc(real_size);
299 }
300
301 if (pointer != nullptr && g_debug->config().options & FILL_ON_ALLOC) {
302 size_t bytes = debug_malloc_usable_size(pointer);
303 size_t fill_bytes = g_debug->config().fill_on_alloc_bytes;
304 bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
305 memset(pointer, g_debug->config().fill_alloc_value, bytes);
306 }
307 return pointer;
308}
309
310void debug_free(void* pointer) {
311 if (DebugCallsDisabled() || pointer == nullptr) {
312 return g_dispatch->free(pointer);
313 }
314
315 void* free_pointer = pointer;
316 size_t bytes;
317 if (g_debug->need_header()) {
318 Header* header = g_debug->GetHeader(pointer);
319 if (header->tag != DEBUG_TAG) {
320 LogTagError(header, pointer, "free");
321 return;
322 }
323 free_pointer = header->orig_pointer;
324
325 if (g_debug->config().options & FRONT_GUARD) {
326 if (!g_debug->front_guard->Valid(*g_debug, header)) {
327 g_debug->front_guard->LogFailure(*g_debug, header);
328 }
329 }
330 if (g_debug->config().options & REAR_GUARD) {
331 if (!g_debug->rear_guard->Valid(*g_debug, header)) {
332 g_debug->rear_guard->LogFailure(*g_debug, header);
333 }
334 }
335
336 if (g_debug->config().options & TRACK_ALLOCS) {
337 bool backtrace_found = false;
338 if (g_debug->config().options & BACKTRACE) {
339 BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
340 backtrace_found = back_header->num_frames > 0;
341 }
342 g_debug->track->Remove(header, backtrace_found);
343 }
344
345 if (g_debug->config().options & FREE_TRACK) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800346 g_debug->free_track->Add(*g_debug, header);
347
348 // Do not free this pointer just yet.
349 free_pointer = nullptr;
350 }
Christopher Ferris7993b802016-01-28 18:35:05 -0800351 header->tag = DEBUG_FREE_TAG;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800352
353 bytes = header->usable_size;
354 } else {
355 bytes = g_dispatch->malloc_usable_size(pointer);
356 }
357
358 if (g_debug->config().options & FILL_ON_FREE) {
359 size_t fill_bytes = g_debug->config().fill_on_free_bytes;
360 bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
361 memset(pointer, g_debug->config().fill_free_value, bytes);
362 }
363
364 g_dispatch->free(free_pointer);
365}
366
367void* debug_memalign(size_t alignment, size_t bytes) {
368 if (DebugCallsDisabled()) {
369 return g_dispatch->memalign(alignment, bytes);
370 }
371
372 void* pointer;
373 if (g_debug->need_header()) {
374 if (bytes > Header::max_size()) {
375 errno = ENOMEM;
376 return nullptr;
377 }
378
379 // Make the alignment a power of two.
380 if (!powerof2(alignment)) {
381 alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment);
382 }
383 // Force the alignment to at least sizeof(uintptr_t) to guarantee
384 // that the header is aligned properly.
385 if (alignment < sizeof(uintptr_t)) {
386 alignment = sizeof(uintptr_t);
387 }
388
389 // We don't have any idea what the natural alignment of
390 // the underlying native allocator is, so we always need to
391 // over allocate.
392 size_t real_size = alignment + bytes + g_debug->extra_bytes();
393 if (real_size < bytes) {
394 // Overflow.
395 errno = ENOMEM;
396 return nullptr;
397 }
398
399 pointer = g_dispatch->malloc(real_size);
400 if (pointer == nullptr) {
401 return nullptr;
402 }
403
404 uintptr_t value = reinterpret_cast<uintptr_t>(pointer) + g_debug->pointer_offset();
405 // Now align the pointer.
406 value += (-value % alignment);
407
408 Header* header = g_debug->GetHeader(reinterpret_cast<void*>(value));
409 pointer = InitHeader(header, pointer, bytes);
410 } else {
411 size_t real_size = bytes + g_debug->extra_bytes();
412 if (real_size < bytes) {
413 // Overflow.
414 errno = ENOMEM;
415 return nullptr;
416 }
417 pointer = g_dispatch->memalign(alignment, real_size);
418 }
419
420 if (pointer != nullptr && g_debug->config().options & FILL_ON_ALLOC) {
421 size_t bytes = debug_malloc_usable_size(pointer);
422 size_t fill_bytes = g_debug->config().fill_on_alloc_bytes;
423 bytes = (bytes < fill_bytes) ? bytes : fill_bytes;
424 memset(pointer, g_debug->config().fill_alloc_value, bytes);
425 }
426 return pointer;
427}
428
429void* debug_realloc(void* pointer, size_t bytes) {
430 if (DebugCallsDisabled()) {
431 return g_dispatch->realloc(pointer, bytes);
432 }
433
434 if (pointer == nullptr) {
435 return debug_malloc(bytes);
436 }
437
438 if (bytes == 0) {
439 debug_free(pointer);
440 return nullptr;
441 }
442
443 size_t real_size = bytes;
444 if (g_debug->config().options & EXPAND_ALLOC) {
445 real_size += g_debug->config().expand_alloc_bytes;
446 if (real_size < bytes) {
447 // Overflow.
448 errno = ENOMEM;
449 return nullptr;
450 }
451 }
452
453 void* new_pointer;
454 size_t prev_size;
455 if (g_debug->need_header()) {
456 if (bytes > Header::max_size()) {
457 errno = ENOMEM;
458 return nullptr;
459 }
460
461 Header* header = g_debug->GetHeader(pointer);
462 if (header->tag != DEBUG_TAG) {
463 LogTagError(header, pointer, "realloc");
464 return nullptr;
465 }
466
467 // Same size, do nothing.
468 if (real_size == header->real_size()) {
469 return pointer;
470 }
471
472 // Allocation is shrinking.
473 if (real_size < header->usable_size) {
474 header->size = real_size;
475 if (*g_malloc_zygote_child) {
476 header->set_zygote();
477 }
478 if (g_debug->config().options & REAR_GUARD) {
479 // Don't bother allocating a smaller pointer in this case, simply
480 // change the header usable_size and reset the rear guard.
481 header->usable_size = header->real_size();
482 memset(g_debug->GetRearGuard(header), g_debug->config().rear_guard_value,
483 g_debug->config().rear_guard_bytes);
484 }
485 return pointer;
486 }
487
488 // Allocate the new size.
489 new_pointer = debug_malloc(bytes);
490 if (new_pointer == nullptr) {
491 errno = ENOMEM;
492 return nullptr;
493 }
494
495 prev_size = header->usable_size;
496 memcpy(new_pointer, pointer, prev_size);
497 debug_free(pointer);
498 } else {
499 prev_size = g_dispatch->malloc_usable_size(pointer);
500 new_pointer = g_dispatch->realloc(pointer, real_size);
501 if (new_pointer == nullptr) {
502 return nullptr;
503 }
504 }
505
506 if (g_debug->config().options & FILL_ON_ALLOC) {
507 size_t bytes = debug_malloc_usable_size(new_pointer);
508 if (bytes > g_debug->config().fill_on_alloc_bytes) {
509 bytes = g_debug->config().fill_on_alloc_bytes;
510 }
511 if (bytes > prev_size) {
512 memset(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(new_pointer) + prev_size),
513 g_debug->config().fill_alloc_value, bytes - prev_size);
514 }
515 }
516
517 return new_pointer;
518}
519
520void* debug_calloc(size_t nmemb, size_t bytes) {
521 if (DebugCallsDisabled()) {
522 return g_dispatch->calloc(nmemb, bytes);
523 }
524
525 size_t real_size = nmemb * bytes + g_debug->extra_bytes();
526 if (real_size < bytes || real_size < nmemb) {
527 // Overflow.
528 errno = ENOMEM;
529 return nullptr;
530 }
531
532 if (g_debug->need_header()) {
533 // The above check will guarantee the multiply will not overflow.
534 if (bytes * nmemb > Header::max_size()) {
535 errno = ENOMEM;
536 return nullptr;
537 }
538
539 // Need to guarantee the alignment of the header.
540 Header* header = reinterpret_cast<Header*>(g_dispatch->memalign(sizeof(uintptr_t), real_size));
541 if (header == nullptr) {
542 return nullptr;
543 }
544 memset(header, 0, g_dispatch->malloc_usable_size(header));
545 return InitHeader(header, header, nmemb * bytes);
546 } else {
547 return g_dispatch->calloc(1, real_size);
548 }
549}
550
551struct mallinfo debug_mallinfo() {
552 return g_dispatch->mallinfo();
553}
554
555int debug_posix_memalign(void** memptr, size_t alignment, size_t size) {
556 if (DebugCallsDisabled()) {
557 return g_dispatch->posix_memalign(memptr, alignment, size);
558 }
559
560 if (!powerof2(alignment)) {
561 return EINVAL;
562 }
563 int saved_errno = errno;
564 *memptr = debug_memalign(alignment, size);
565 errno = saved_errno;
566 return (*memptr != nullptr) ? 0 : ENOMEM;
567}
568
569#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
570void* debug_pvalloc(size_t bytes) {
571 if (DebugCallsDisabled()) {
572 return g_dispatch->pvalloc(bytes);
573 }
574
575 size_t pagesize = getpagesize();
576 size_t size = BIONIC_ALIGN(bytes, pagesize);
577 if (size < bytes) {
578 // Overflow
579 errno = ENOMEM;
580 return nullptr;
581 }
582 return debug_memalign(pagesize, size);
583}
584
585void* debug_valloc(size_t size) {
586 if (DebugCallsDisabled()) {
587 return g_dispatch->valloc(size);
588 }
589 return debug_memalign(getpagesize(), size);
590}
591#endif