From c4eee3765bf9dd81ff055e70ff7daa83a3926d2a Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Wed, 8 Jul 2009 14:22:41 +0200 Subject: [PATCH 1/6] Prevent a crash in the memory leak checker (which happened in chk_free()) Simplify the code a little, removing un-necessary mutex locks/unlocks. Provide slightly better diagnostic message in case of corruption. Use snprintf/strlcat instead of sprintf/strcat --- libc/bionic/logd_write.c | 8 +-- libc/bionic/malloc_leak.c | 140 ++++++++++++++++++++++---------------- libc/private/logd.h | 3 + 3 files changed, 88 insertions(+), 63 deletions(-) diff --git a/libc/bionic/logd_write.c b/libc/bionic/logd_write.c index 7c3608bf7..211b5279f 100644 --- a/libc/bionic/logd_write.c +++ b/libc/bionic/logd_write.c @@ -126,10 +126,10 @@ static int __android_log_write(int prio, const char *tag, const char *msg) } -static int __android_log_vprint(int prio, const char *tag, const char *fmt, - va_list ap) +int __libc_android_log_vprint(int prio, const char *tag, const char *fmt, + va_list ap) { - char buf[LOG_BUF_SIZE]; + char buf[LOG_BUF_SIZE]; vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); @@ -139,7 +139,7 @@ static int __android_log_vprint(int prio, const char *tag, const char *fmt, int __libc_android_log_print(int prio, const char *tag, const char *fmt, ...) { va_list ap; - char buf[LOG_BUF_SIZE]; + char buf[LOG_BUF_SIZE]; va_start(ap, fmt); vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); diff --git a/libc/bionic/malloc_leak.c b/libc/bionic/malloc_leak.c index a0aa2ae64..df09424b3 100644 --- a/libc/bionic/malloc_leak.c +++ b/libc/bionic/malloc_leak.c @@ -515,8 +515,8 @@ static void dump_stack_trace() tmp[0] = 0; // Need to initialize tmp[0] for the first strcat for (i=0 ; i=0 ; i--) { if (buf[i] != CHK_SENTINEL_VALUE) { - gMallocDispatch = &gMallocEngineTable[INDEX_NORMAL]; - __libc_android_log_print(ANDROID_LOG_ERROR, "libc", - "*** MALLOC CHECK: buffer %p, size=%lu, " - "corrupted %d bytes after allocation", - buffer, size, i+1); - dump_stack_trace(); - if (gTrapOnError) { - __builtin_trap(); - } - gMallocDispatch = &gMallocEngineTable[INDEX_MALLOC_CHECK]; + assert_log_message( + "*** %s CHECK: buffer %p, size=%lu, " + "corrupted %d bytes after allocation", + func, buffer, bytes, i+1); + return -1; } } + + *allocated = bytes; + return 0; } + void* chk_malloc(size_t bytes) { char* buffer = (char*)dlmalloc(bytes + CHK_OVERHEAD_SIZE); if (buffer) { - pthread_mutex_lock(&gAllocationsMutex); - memset(buffer, CHK_SENTINEL_VALUE, bytes + CHK_OVERHEAD_SIZE); - size_t offset = dlmalloc_usable_size(buffer) - sizeof(size_t); - *(size_t *)(buffer + offset) = bytes; - buffer += CHK_SENTINEL_HEAD_SIZE; - pthread_mutex_unlock(&gAllocationsMutex); + memset(buffer, CHK_SENTINEL_VALUE, bytes + CHK_OVERHEAD_SIZE); + size_t offset = dlmalloc_usable_size(buffer) - sizeof(size_t); + *(size_t *)(buffer + offset) = bytes; + buffer += CHK_SENTINEL_HEAD_SIZE; } return buffer; } @@ -597,14 +618,14 @@ void chk_free(void* mem) { assert_valid_malloc_pointer(mem); if (mem) { - pthread_mutex_lock(&gAllocationsMutex); - char* buffer = (char*)mem - CHK_SENTINEL_HEAD_SIZE; - size_t offset = dlmalloc_usable_size(buffer) - sizeof(size_t); - size_t bytes = *(size_t *)(buffer + offset); - chk_out_of_bounds_check__locked(mem, bytes); - pthread_mutex_unlock(&gAllocationsMutex); - memset(buffer, CHK_FILL_FREE, bytes); - dlfree(buffer); + size_t size; + char* buffer; + + if (chk_mem_check(mem, &size, "FREE") == 0) { + buffer = (char*)mem - CHK_SENTINEL_HEAD_SIZE; + memset(buffer, CHK_FILL_FREE, size + CHK_OVERHEAD_SIZE); + dlfree(buffer); + } } } @@ -628,19 +649,20 @@ void* chk_calloc(size_t n_elements, size_t elem_size) void* chk_realloc(void* mem, size_t bytes) { + char* buffer; + int ret; + size_t old_bytes = 0; + assert_valid_malloc_pointer(mem); + + if (mem != NULL && chk_mem_check(mem, &old_bytes, "REALLOC") < 0) + return NULL; + char* new_buffer = chk_malloc(bytes); if (mem == NULL) { return new_buffer; } - pthread_mutex_lock(&gAllocationsMutex); - char* buffer = (char*)mem - CHK_SENTINEL_HEAD_SIZE; - size_t offset = dlmalloc_usable_size(buffer) - sizeof(size_t); - size_t old_bytes = *(size_t *)(buffer + offset); - chk_out_of_bounds_check__locked(mem, old_bytes); - pthread_mutex_unlock(&gAllocationsMutex); - if (new_buffer) { size_t size = (bytes < old_bytes)?(bytes):(old_bytes); memcpy(new_buffer, mem, size); diff --git a/libc/private/logd.h b/libc/private/logd.h index 671cb4802..43fa74235 100644 --- a/libc/private/logd.h +++ b/libc/private/logd.h @@ -28,6 +28,8 @@ #ifndef _ANDROID_BIONIC_LOGD_H #define _ANDROID_BIONIC_LOGD_H +#include + enum { ANDROID_LOG_UNKNOWN = 0, ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */ @@ -43,5 +45,6 @@ enum { }; int __libc_android_log_print(int prio, const char *tag, const char *fmt, ...); +int __libc_android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap); #endif /* _ANDROID_BIONIC_LOGD_H */ From db4616b2d3234a1916cafb48e65c50cf302afcde Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Fri, 10 Jul 2009 00:59:56 +0200 Subject: [PATCH 2/6] Add to C library kernel headers --- libc/kernel/common/linux/uinput.h | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 libc/kernel/common/linux/uinput.h diff --git a/libc/kernel/common/linux/uinput.h b/libc/kernel/common/linux/uinput.h new file mode 100644 index 000000000..b7a6addc3 --- /dev/null +++ b/libc/kernel/common/linux/uinput.h @@ -0,0 +1,67 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef __UINPUT_H_ +#define __UINPUT_H_ + +#include + +#define UINPUT_VERSION 3 + +struct uinput_ff_upload { + int request_id; + int retval; + struct ff_effect effect; + struct ff_effect old; +}; + +struct uinput_ff_erase { + int request_id; + int retval; + int effect_id; +}; + +#define UINPUT_IOCTL_BASE 'U' +#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1) +#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2) + +#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) +#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) +#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) +#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int) +#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int) +#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int) +#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int) +#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int) +#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*) +#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int) + +#define UI_BEGIN_FF_UPLOAD _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload) +#define UI_END_FF_UPLOAD _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload) +#define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) +#define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) + +#define EV_UINPUT 0x0101 +#define UI_FF_UPLOAD 1 +#define UI_FF_ERASE 2 + +#define UINPUT_MAX_NAME_SIZE 80 +struct uinput_user_dev { + char name[UINPUT_MAX_NAME_SIZE]; + struct input_id id; + int ff_effects_max; + int absmax[ABS_MAX + 1]; + int absmin[ABS_MAX + 1]; + int absfuzz[ABS_MAX + 1]; + int absflat[ABS_MAX + 1]; +}; +#endif + From 348065586a2e6154d6cff36afa6e00af6bbc5918 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Fri, 10 Jul 2009 12:23:09 +0200 Subject: [PATCH 3/6] Add new C++ headers and Also add std::malloc/realloc/calloc/free to Rename to --- libstdc++/include/cerrno | 40 +++++++++++++++++++ libstdc++/include/cfloat | 39 ++++++++++++++++++ libstdc++/include/cstdlib | 5 +++ .../{cwchar_is_not_supported => cwchar} | 0 4 files changed, 84 insertions(+) create mode 100644 libstdc++/include/cerrno create mode 100644 libstdc++/include/cfloat rename libstdc++/include/{cwchar_is_not_supported => cwchar} (100%) diff --git a/libstdc++/include/cerrno b/libstdc++/include/cerrno new file mode 100644 index 000000000..e53ca2571 --- /dev/null +++ b/libstdc++/include/cerrno @@ -0,0 +1,40 @@ +/* -*- c++ -*- */ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CERRNO__ +#define BIONIC_LIBSTDCPP_INCLUDE_CERRNO__ + +/* + * Standard C++ Library wrapper around the C errno.h header file. + */ +#include + +// errno is a macro, so we can't define std::errno + +#endif // BIONIC_LIBSTDCPP_INCLUDE_CERRNO__ diff --git a/libstdc++/include/cfloat b/libstdc++/include/cfloat new file mode 100644 index 000000000..21c01d9c9 --- /dev/null +++ b/libstdc++/include/cfloat @@ -0,0 +1,39 @@ +/* -*- c++ -*- */ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef BIONIC_LIBSTDCPP_INCLUDE_CFLOAT__ +#define BIONIC_LIBSTDCPP_INCLUDE_CFLOAT__ + +/* + * Standard C++ Library wrapper around the C float.h header file. + */ +#include +#include + +#endif // BIONIC_LIBSTDCPP_INCLUDE_CFLOAT__ diff --git a/libstdc++/include/cstdlib b/libstdc++/include/cstdlib index 9e8a7ced4..5e6a0b37a 100644 --- a/libstdc++/include/cstdlib +++ b/libstdc++/include/cstdlib @@ -85,6 +85,11 @@ using ::srand; using ::random; using ::srandom; +using ::malloc; +using ::free; +using ::calloc; +using ::realloc; + using ::unlockpt; using ::ptsname; using ::ptsname_r; diff --git a/libstdc++/include/cwchar_is_not_supported b/libstdc++/include/cwchar similarity index 100% rename from libstdc++/include/cwchar_is_not_supported rename to libstdc++/include/cwchar From ef0bd1857041ffde069cf52138aaf22c1af7130e Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Fri, 17 Jul 2009 17:55:01 +0200 Subject: [PATCH 4/6] Pass the elfdata pointer in a slot of the temporary TLS area. This is needed to properly initialize the C runtime when libc.so is loaded by the dynamic linker. Move the temporary TLS setup before the first system call, just in case something really horrible happens, we won't crash when trying to write an error code in 'errno' Remove the broken TLS_SLOT_THREAD_ID setup. First, this slot should normally receive the address of a pthread_internal_t, not a kernel thread identifier. Second, it is never used by the linker anyway. Also remove an obsolete comment. --- libc/private/bionic_tls.h | 7 +++++++ linker/linker.c | 21 ++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h index da343441f..82c8cd909 100644 --- a/libc/private/bionic_tls.h +++ b/libc/private/bionic_tls.h @@ -60,6 +60,13 @@ __BEGIN_DECLS #define TLS_SLOT_OPENGL_API 3 #define TLS_SLOT_OPENGL 4 +/* this slot is only used to pass information from the dynamic linker to + * libc.so when the C library is loaded in to memory. The C runtime init + * function will then clear it. Since its use is extremely temporary, + * we reuse an existing location. + */ +#define TLS_SLOT_BIONIC_PREINIT (TLS_SLOT_ERRNO+1) + /* small technical note: it is not possible to call pthread_setspecific * on keys that are <= TLS_SLOT_MAX_WELL_KNOWN, which is why it is set to * TLS_SLOT_ERRNO. diff --git a/linker/linker.c b/linker/linker.c index 77f995ea8..e23549853 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -76,11 +76,6 @@ * headers provide versions that are negative... * - allocate space for soinfo structs dynamically instead of * having a hard limit (64) - * - * features to add someday: - * - * - dlopen() and friends - * */ @@ -1744,6 +1739,11 @@ unsigned __linker_init(unsigned **elfdata) struct link_map * map; char *ldpath_env = NULL; + /* Setup a temporary TLS area that is used to get a working + * errno for system calls. + */ + __set_tls(__tls_area); + pid = getpid(); #if TIMING @@ -1751,8 +1751,15 @@ unsigned __linker_init(unsigned **elfdata) gettimeofday(&t0, 0); #endif - __set_tls(__tls_area); - ((unsigned *)__get_tls())[TLS_SLOT_THREAD_ID] = gettid(); + /* NOTE: we store the elfdata pointer on a special location + * of the temporary TLS area in order to pass it to + * the C Library's runtime initializer. + * + * The initializer must clear the slot and reset the TLS + * to point to a different location to ensure that no other + * shared library constructor can access it. + */ + __tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata; debugger_init(); From b56b5659b3996e98c2060f168d1cff1474e77d2a Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Sat, 18 Jul 2009 01:11:10 +0200 Subject: [PATCH 5/6] Fix the C library runtime initialization order. This allows libc.so to run the C runtime initializer as soon as the dynamic linker loads the shared library, i.e. before any other initializers (e.g. static C++ constructors in other shared libraries the executable depends on). This also removes the bug where the initializers from the executable itself were run twice: once by the dynamic linker, and another time by __libc_init as defined by libc_init_dynamic.c --- libc/bionic/libc_init_common.c | 81 +++++++++++---------------------- libc/bionic/libc_init_common.h | 6 +-- libc/bionic/libc_init_dynamic.c | 69 ++++++++++++++++++++-------- libc/bionic/libc_init_static.c | 63 +++++++++++++++---------- 4 files changed, 117 insertions(+), 102 deletions(-) diff --git a/libc/bionic/libc_init_common.c b/libc/bionic/libc_init_common.c index de4919d27..c77c162c5 100644 --- a/libc/bionic/libc_init_common.c +++ b/libc/bionic/libc_init_common.c @@ -39,23 +39,6 @@ #include #include -extern void _init(void); -extern void _fini(void); - -static void call_array(void(**list)()) -{ - // First element is -1, list is null-terminated - while (*++list) { - (*list)(); - } -} - -static void __bionic_do_global_dtors(structors_array_t const * const p) -{ - call_array(p->fini_array); - //_fini(); -} - extern unsigned __get_sp(void); extern pid_t gettid(void); @@ -69,23 +52,23 @@ unsigned int __page_shift = PAGE_SHIFT; int __system_properties_init(void); -void __libc_init_common(uintptr_t *elfdata, - void (*onexit)(void), - int (*slingshot)(int, char**, char**), - structors_array_t const * const structors, - void (*pre_ctor_hook)()) -{ - pthread_internal_t thread; - pthread_attr_t thread_attr; - void *tls_area[BIONIC_TLS_SLOTS]; - int argc; - char **argv, **envp, **envend; - struct auxentry *auxentry; - unsigned int page_size = 0, page_shift = 0; +#ifdef MALLOCK_LEAK_CHECK +void malloc_debug_init(void); +#endif - /* The main thread's stack has empirically shown to be 84k */ +void __libc_init_common(uintptr_t *elfdata) +{ + int argc = *elfdata; + char** argv = (char**)(elfdata + 1); + char** envp = argv + argc + 1; + + pthread_attr_t thread_attr; + static pthread_internal_t thread; + static void* tls_area[BIONIC_TLS_SLOTS]; + + /* setup pthread runtime and maint thread descriptor */ unsigned stacktop = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE; - unsigned stacksize = 128 * 1024; //84 * 1024; + unsigned stacksize = 128 * 1024; unsigned stackbottom = stacktop - stacksize; pthread_attr_init(&thread_attr); @@ -93,30 +76,20 @@ void __libc_init_common(uintptr_t *elfdata, _init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom); __init_tls(tls_area, &thread); - argc = (int) *elfdata++; - argv = (char**) elfdata; - envp = argv+(argc+1); - environ = envp; - - __progname = argv[0] ? argv[0] : ""; - + /* clear errno - requires TLS area */ errno = 0; + /* set program name */ + __progname = argv[0] ? argv[0] : ""; + + /* setup environment pointer */ + environ = envp; + + /* setup system properties - requires environment */ __system_properties_init(); - if (pre_ctor_hook) pre_ctor_hook(); - - // XXX: we should execute the .fini_array upon exit - - // pre-init array. - // XXX: I'm not sure what's the different with the init array. - call_array(structors->preinit_array); - - // for compatibility with non-eabi binary, call the .ctors section - call_array(structors->ctors_array); - - // call static constructors - call_array(structors->init_array); - - exit(slingshot(argc, argv, envp)); + /* setup malloc leak checker, requires system properties */ +#if MALLOC_LEAK_CHECK + malloc_debug_init(); +#endif } diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h index bbc82e4b7..8663c611b 100644 --- a/libc/bionic/libc_init_common.h +++ b/libc/bionic/libc_init_common.h @@ -38,10 +38,6 @@ typedef struct void (**ctors_array)(void); } structors_array_t; -extern __noreturn void __libc_init_common(uintptr_t *elfdata, - void (*onexit)(void), - int (*slingshot)(int, char**, char**), - structors_array_t const * const structors, - void (*pre_ctor_hook)()); +extern void __libc_init_common(uintptr_t *elfdata); #endif diff --git a/libc/bionic/libc_init_dynamic.c b/libc/bionic/libc_init_dynamic.c index 8cf24b466..b8e10782f 100644 --- a/libc/bionic/libc_init_dynamic.c +++ b/libc/bionic/libc_init_dynamic.c @@ -26,41 +26,74 @@ * SUCH DAMAGE. */ /* - * libc_init_static.c + * libc_init_dynamic.c * - * This function takes the raw data block set up by the ELF loader - * in the kernel and parses it. It is invoked by crt0.S which makes - * any necessary adjustments and passes calls this function using - * the standard C calling convention. + * This source files provides two important functions for dynamic + * executables: * - * The arguments are: - * uintptr_t *elfdata -- The ELF loader data block; usually from the stack. - * Basically a pointer to argc. - * void (*onexit)(void) -- Function to install into onexit + * - a C runtime initializer (__libc_preinit), which is called by + * the dynamic linker when libc.so is loaded. This happens before + * any other initializer (e.g. static C++ constructors in other + * shared libraries the program depends on). + * + * - a program launch function (__libc_init), which is called after + * all dynamic linking has been performed. Technically, it is called + * from arch-$ARCH/bionic/crtbegin_dynamic.S which is itself called + * by the dynamic linker after all libraries have been loaded and + * initialized. */ -/* - * Several Linux ABIs don't pass the onexit pointer, and the ones that - * do never use it. Therefore, unless USE_ONEXIT is defined, we just - * ignore the onexit pointer. - */ -/* #define USE_ONEXIT */ - #include #include #include #include #include -#include "pthread_internal.h" #include "atexit.h" #include "libc_init_common.h" +#include extern void malloc_debug_init(); +/* We flag the __libc_preinit function as a constructor to ensure + * that its address is listed in libc.so's .init_array section. + * This ensures that the function is called by the dynamic linker + * as soon as the shared library is loaded. + */ +void __attribute__((constructor)) __libc_prenit(void); + +void __libc_prenit(void) +{ + /* Read the ELF data pointer form a special slot of the + * TLS area, then call __libc_init_common with it. + * + * Note that: + * - we clear the slot so no other initializer sees its value. + * - __libc_init_common() will change the TLS area so the old one + * won't be accessible anyway. + */ + void** tls_area = (void**)__get_tls(); + unsigned* elfdata = tls_area[TLS_SLOT_BIONIC_PREINIT]; + + tls_area[TLS_SLOT_BIONIC_PREINIT] = NULL; + + __libc_init_common(elfdata); +} + __noreturn void __libc_init(uintptr_t *elfdata, void (*onexit)(void), int (*slingshot)(int, char**, char**), structors_array_t const * const structors) { - __libc_init_common(elfdata, onexit, slingshot, structors, malloc_debug_init); + /* When we reach this point, all initializers have been already + * run by the dynamic linker, so ignore 'structors'. + */ + int argc = (int)*elfdata; + char** argv = (char**)(elfdata + 1); + char** envp = argv + argc + 1; + + /* Several Linux ABIs don't pass the onexit pointer, and the ones that + * do never use it. Therefore, we ignore it. + */ + + exit(slingshot(argc, argv, envp)); } diff --git a/libc/bionic/libc_init_static.c b/libc/bionic/libc_init_static.c index ec463f7ec..d097b6baf 100644 --- a/libc/bionic/libc_init_static.c +++ b/libc/bionic/libc_init_static.c @@ -28,24 +28,15 @@ /* * libc_init_static.c * - * This function takes the raw data block set up by the ELF loader - * in the kernel and parses it. It is invoked by crt0.S which makes - * any necessary adjustments and passes calls this function using - * the standard C calling convention. + * The program startup function __libc_init() defined here is + * used for static executables only (i.e. those that don't depend + * on shared libraries). It is called from arch-$ARCH/bionic/crtbegin_static.S + * which is directly invoked by the kernel when the program is launched. * - * The arguments are: - * uintptr_t *elfdata -- The ELF loader data block; usually from the stack. - * Basically a pointer to argc. - * void (*onexit)(void) -- Function to install into onexit + * The 'structors' parameter contains pointers to various initializer + * arrays that must be run before the program's 'main' routine is launched. */ -/* - * Several Linux ABIs don't pass the onexit pointer, and the ones that - * do never use it. Therefore, unless USE_ONEXIT is defined, we just - * ignore the onexit pointer. - */ -/* #define USE_ONEXIT */ - #include #include #include @@ -58,19 +49,41 @@ #include #include +static void call_array(void(**list)()) +{ + // First element is -1, list is null-terminated + while (*++list) { + (*list)(); + } +} + __noreturn void __libc_init(uintptr_t *elfdata, void (*onexit)(void), int (*slingshot)(int, char**, char**), structors_array_t const * const structors) { -/* - * To enable malloc checks for statically linked programs, add - * "WITH_MALLOC_CHECK_LIBC_A := true" in device/buildspec.mk - */ -#ifdef MALLOC_LEAK_CHECK - extern void malloc_debug_init(); - __libc_init_common(elfdata, onexit, slingshot, structors, malloc_debug_init); -#else - __libc_init_common(elfdata, onexit, slingshot, structors, NULL); -#endif + int argc; + char **argv, **envp; + + /* Initialize the C runtime environment */ + __libc_init_common(elfdata); + + /* Several Linux ABIs don't pass the onexit pointer, and the ones that + * do never use it. Therefore, we ignore it. + */ + + /* pre-init array. */ + call_array(structors->preinit_array); + + /* .ctors section initializers, for non-arm-eabi ABIs */ + call_array(structors->ctors_array); + + // call static constructors + call_array(structors->init_array); + + argc = (int) *elfdata; + argv = (char**)(elfdata + 1); + envp = argv + argc + 1; + + exit(slingshot(argc, argv, envp)); } From 39f3745cf30efe38482ffead1c32f4e62f6fe32e Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Tue, 21 Jul 2009 15:25:23 -0700 Subject: [PATCH 6/6] Restore malloc debug. Some libc changes were preventing the initialization call from being made. The basic problem appears to be that libc_init_common.c is only built once, and it's only built for the non-debug libc. --- libc/bionic/libc_init_common.c | 9 --------- libc/bionic/libc_init_dynamic.c | 7 +++++++ libc/bionic/libc_init_static.c | 6 ++++++ libc/bionic/malloc_leak.c | 15 ++++++++------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libc/bionic/libc_init_common.c b/libc/bionic/libc_init_common.c index c77c162c5..d78d673f0 100644 --- a/libc/bionic/libc_init_common.c +++ b/libc/bionic/libc_init_common.c @@ -52,10 +52,6 @@ unsigned int __page_shift = PAGE_SHIFT; int __system_properties_init(void); -#ifdef MALLOCK_LEAK_CHECK -void malloc_debug_init(void); -#endif - void __libc_init_common(uintptr_t *elfdata) { int argc = *elfdata; @@ -87,9 +83,4 @@ void __libc_init_common(uintptr_t *elfdata) /* setup system properties - requires environment */ __system_properties_init(); - - /* setup malloc leak checker, requires system properties */ -#if MALLOC_LEAK_CHECK - malloc_debug_init(); -#endif } diff --git a/libc/bionic/libc_init_dynamic.c b/libc/bionic/libc_init_dynamic.c index b8e10782f..b479b272f 100644 --- a/libc/bionic/libc_init_dynamic.c +++ b/libc/bionic/libc_init_dynamic.c @@ -77,6 +77,13 @@ void __libc_prenit(void) tls_area[TLS_SLOT_BIONIC_PREINIT] = NULL; __libc_init_common(elfdata); + +#ifdef MALLOC_LEAK_CHECK + /* setup malloc leak checker, requires system properties */ + extern void malloc_debug_init(void); + malloc_debug_init(); +#endif + } __noreturn void __libc_init(uintptr_t *elfdata, diff --git a/libc/bionic/libc_init_static.c b/libc/bionic/libc_init_static.c index d097b6baf..e6264bbc5 100644 --- a/libc/bionic/libc_init_static.c +++ b/libc/bionic/libc_init_static.c @@ -68,6 +68,12 @@ __noreturn void __libc_init(uintptr_t *elfdata, /* Initialize the C runtime environment */ __libc_init_common(elfdata); +#ifdef MALLOC_LEAK_CHECK + /* setup malloc leak checker, requires system properties */ + extern void malloc_debug_init(void); + malloc_debug_init(); +#endif + /* Several Linux ABIs don't pass the onexit pointer, and the ones that * do never use it. Therefore, we ignore it. */ diff --git a/libc/bionic/malloc_leak.c b/libc/bionic/malloc_leak.c index df09424b3..305f954e7 100644 --- a/libc/bionic/malloc_leak.c +++ b/libc/bionic/malloc_leak.c @@ -91,7 +91,14 @@ static pthread_mutex_t gAllocationsMutex = PTHREAD_MUTEX_INITIALIZER; static HashTable gHashTable; // ============================================================================= -// output fucntions +// log functions +// ============================================================================= + +#define debug_log(format, ...) \ + __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_leak", (format), ##__VA_ARGS__ ) + +// ============================================================================= +// output functions // ============================================================================= static int hash_entry_compare(const void* arg1, const void* arg2) @@ -257,12 +264,6 @@ struct AllocationEntry { uint32_t guard; }; -// ============================================================================= -// log funtions -// ============================================================================= - -#define debug_log(format, ...) \ - __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_leak", (format), ##__VA_ARGS__ ) // ============================================================================= // Hash Table functions