Don't corrupt the thread list if the main thread exits.
...and don't pass a non-heap pointer to free(3), either.
This patch replaces the "node** prev" with the clearer "node* prev"
style and fixes the null pointer dereference in the old code. That's
not sufficient to fix the reporter's bug, though. The pthread_internal_t*
for the main thread isn't heap-allocated --- __libc_init_tls causes a
pointer to a statically-allocated pthread_internal_t to be added to
the thread list.
Bug: http://code.google.com/p/android/issues/detail?id=37410
Change-Id: I112b7f22782fc789d58f9c783f7b323bda8fb8b7
diff --git a/libc/bionic/libc_init_common.c b/libc/bionic/libc_init_common.c
index 6508c0b..fb164f4 100644
--- a/libc/bionic/libc_init_common.c
+++ b/libc/bionic/libc_init_common.c
@@ -40,10 +40,10 @@
#include <errno.h>
extern unsigned __get_sp(void);
-extern pid_t gettid(void);
+extern pid_t gettid(void);
char* __progname;
-char **environ;
+char** environ;
/* from asm/page.h */
unsigned int __page_size = PAGE_SIZE;
@@ -60,48 +60,42 @@
* stores the pointer in TLS, but does not add it to pthread's gThreadList. This
* has to be done later from libc itself (see __libc_init_common).
*
- * This function also stores elfdata argument in a specific TLS slot to be later
+ * This function also stores the elf_data argument in a specific TLS slot to be later
* picked up by the libc constructor.
*/
-void __libc_init_tls(unsigned** elfdata)
-{
- pthread_attr_t thread_attr;
- static pthread_internal_t thread;
- static void* tls_area[BIONIC_TLS_SLOTS];
+void __libc_init_tls(unsigned** elf_data) {
+ unsigned stack_top = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
+ unsigned stack_size = 128 * 1024;
+ unsigned stack_bottom = stack_top - stack_size;
- /* setup pthread runtime and main thread descriptor */
- unsigned stacktop = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
- unsigned stacksize = 128 * 1024;
- unsigned stackbottom = stacktop - stacksize;
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setstack(&thread_attr, (void*) stack_bottom, stack_size);
- pthread_attr_init(&thread_attr);
- pthread_attr_setstack(&thread_attr, (void*)stackbottom, stacksize);
- _init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom, false);
- __init_tls(tls_area, &thread);
+ static pthread_internal_t thread;
+ _init_thread(&thread, gettid(), &thread_attr, (void*) stack_bottom, false);
- tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
+ static void* tls_area[BIONIC_TLS_SLOTS];
+ __init_tls(tls_area, &thread);
+ tls_area[TLS_SLOT_BIONIC_PREINIT] = elf_data;
}
-void __libc_init_common(uintptr_t *elfdata)
-{
- int argc = *elfdata;
- char** argv = (char**)(elfdata + 1);
- char** envp = argv + argc + 1;
+void __libc_init_common(uintptr_t* elf_data) {
+ int argc = *elf_data;
+ char** argv = (char**) (elf_data + 1);
+ char** envp = argv + argc + 1;
- /* get the initial thread from TLS and add it to gThreadList */
- _pthread_internal_add(__get_thread());
+ // Get the main thread from TLS and add it to the thread list.
+ pthread_internal_t* main_thread = __get_thread();
+ main_thread->allocated_on_heap = false;
+ _pthread_internal_add(main_thread);
- /* clear errno */
- errno = 0;
+ // Set various globals.
+ errno = 0;
+ __progname = argv[0] ? argv[0] : "<unknown>";
+ environ = envp;
- /* set program name */
- __progname = argv[0] ? argv[0] : "<unknown>";
-
- /* setup environment pointer */
- environ = envp;
-
- /* setup system properties - requires environment */
- __system_properties_init();
+ __system_properties_init(); // Requires 'environ'.
}
/* This function will be called during normal program termination
@@ -111,39 +105,42 @@
* 'fini_array' points to a list of function addresses. The first
* entry in the list has value -1, the last one has value 0.
*/
-void __libc_fini(void* array)
-{
- int count;
- void** fini_array = array;
- const size_t minus1 = ~(size_t)0; /* ensure proper sign extension */
+void __libc_fini(void* array) {
+ void** fini_array = array;
+ const size_t minus1 = ~(size_t)0; /* ensure proper sign extension */
- /* Sanity check - first entry must be -1 */
- if (array == NULL || (size_t)fini_array[0] != minus1) {
- return;
+ /* Sanity check - first entry must be -1 */
+ if (array == NULL || (size_t)fini_array[0] != minus1) {
+ return;
+ }
+
+ /* skip over it */
+ fini_array += 1;
+
+ /* Count the number of destructors. */
+ int count = 0;
+ while (fini_array[count] != NULL) {
+ ++count;
+ }
+
+ /* Now call each destructor in reverse order. */
+ while (count > 0) {
+ void (*func)() = (void (*)) fini_array[--count];
+
+ /* Sanity check, any -1 in the list is ignored */
+ if ((size_t)func == minus1) {
+ continue;
}
- /* skip over it */
- fini_array += 1;
-
- /* Count the number of destructors. */
- for (count = 0; fini_array[count] != NULL; count++);
-
- /* Now call each destructor in reverse order. */
- while (count > 0) {
- void (*func)() = (void (*)) fini_array[--count];
-
- /* Sanity check, any -1 in the list is ignored */
- if ((size_t)func == minus1)
- continue;
-
- func();
- }
+ func();
+ }
#ifndef LIBC_STATIC
- {
- extern void __libc_postfini(void) __attribute__((weak));
- if (__libc_postfini)
- __libc_postfini();
+ {
+ extern void __libc_postfini(void) __attribute__((weak));
+ if (__libc_postfini) {
+ __libc_postfini();
}
+ }
#endif
}