diff options
-rw-r--r-- | libc/Android.mk | 5 | ||||
-rw-r--r-- | libc/bionic/abort.cpp | 1 | ||||
-rw-r--r-- | libc/bionic/libc_init_common.cpp | 1 | ||||
-rw-r--r-- | libc/bionic/libc_init_dynamic.cpp | 2 | ||||
-rw-r--r-- | libc/bionic/libc_init_static.cpp | 3 | ||||
-rw-r--r-- | libc/private/thread_private.h | 8 | ||||
-rw-r--r-- | libc/upstream-openbsd/android/include/openbsd-compat.h | 2 | ||||
-rw-r--r-- | libc/upstream-openbsd/android/include/thread_private.h | 26 | ||||
-rw-r--r-- | libc/upstream-openbsd/lib/libc/stdlib/atexit.c (renamed from libc/stdlib/atexit.c) | 150 | ||||
-rw-r--r-- | libc/upstream-openbsd/lib/libc/stdlib/atexit.h (renamed from libc/stdlib/atexit.h) | 12 |
10 files changed, 68 insertions, 142 deletions
diff --git a/libc/Android.mk b/libc/Android.mk index 765f4d2..59cc3b8 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -67,7 +67,6 @@ libc_common_src_files := \ bionic/unlockpt.c \ stdio/snprintf.c\ stdio/sprintf.c \ - stdlib/atexit.c \ unistd/syslog.c \ # Fortify implementations of libc functions. @@ -463,6 +462,7 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/stdio/wprintf.c \ upstream-openbsd/lib/libc/stdio/wscanf.c \ upstream-openbsd/lib/libc/stdio/wsetup.c \ + upstream-openbsd/lib/libc/stdlib/atexit.c \ upstream-openbsd/lib/libc/stdlib/atoi.c \ upstream-openbsd/lib/libc/stdlib/atol.c \ upstream-openbsd/lib/libc/stdlib/atoll.c \ @@ -549,7 +549,6 @@ libc_common_cppflags := \ # Define some common includes # ======================================================== libc_common_c_includes += \ - $(LOCAL_PATH)/stdlib \ $(LOCAL_PATH)/stdio \ # ======================================================== @@ -735,6 +734,7 @@ LOCAL_SRC_FILES := $(libc_upstream_openbsd_src_files) LOCAL_CFLAGS := \ $(libc_common_cflags) \ -Wno-sign-compare -Wno-uninitialized -Wno-unused-parameter \ + -I$(LOCAL_PATH)/private \ -I$(LOCAL_PATH)/upstream-openbsd/android/include \ -I$(LOCAL_PATH)/upstream-openbsd/lib/libc/include \ -I$(LOCAL_PATH)/upstream-openbsd/lib/libc/gdtoa/ \ @@ -767,6 +767,7 @@ LOCAL_CFLAGS := \ $(libc_common_cflags) \ -Wno-sign-compare -Wno-uninitialized \ -fvisibility=hidden \ + -I$(LOCAL_PATH)/private \ -I$(LOCAL_PATH)/upstream-openbsd/android/include \ -I$(LOCAL_PATH)/upstream-openbsd/lib/libc/include \ -include openbsd-compat.h \ diff --git a/libc/bionic/abort.cpp b/libc/bionic/abort.cpp index 69ac0e5..75413c6 100644 --- a/libc/bionic/abort.cpp +++ b/libc/bionic/abort.cpp @@ -30,7 +30,6 @@ #include <signal.h> #include <stdlib.h> #include <unistd.h> -#include "atexit.h" #ifdef __arm__ extern "C" __LIBC_HIDDEN__ void __libc_android_abort() diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp index fa61c3c..aa76650 100644 --- a/libc/bionic/libc_init_common.cpp +++ b/libc/bionic/libc_init_common.cpp @@ -39,7 +39,6 @@ #include <sys/resource.h> #include <unistd.h> -#include "atexit.h" #include "private/bionic_auxv.h" #include "private/bionic_ssp.h" #include "private/bionic_tls.h" diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index 7c46364..78125f9 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -48,7 +48,6 @@ #include <stdlib.h> #include <stdint.h> #include <elf.h> -#include "atexit.h" #include "libc_init_common.h" #include "private/bionic_tls.h" @@ -58,6 +57,7 @@ extern "C" { extern void malloc_debug_init(void); extern void malloc_debug_fini(void); extern void netdClientInit(void); + extern int __cxa_atexit(void (*)(void *), void *, void *); }; // We flag the __libc_preinit function as a constructor to ensure diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp index ab0b3a6..bc11f3d 100644 --- a/libc/bionic/libc_init_static.cpp +++ b/libc/bionic/libc_init_static.cpp @@ -46,7 +46,6 @@ #include <sys/auxv.h> #include <sys/mman.h> -#include "atexit.h" #include "libc_init_common.h" #include "pthread_internal.h" @@ -60,6 +59,8 @@ // itself at the start of a page. #define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1)) +extern "C" int __cxa_atexit(void (*)(void *), void *, void *); + static void call_array(void(**list)()) { // First element is -1, list is null-terminated while (*++list) { diff --git a/libc/private/thread_private.h b/libc/private/thread_private.h index 724808a..b8b1a81 100644 --- a/libc/private/thread_private.h +++ b/libc/private/thread_private.h @@ -33,8 +33,12 @@ struct __thread_private_tag_t { #define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \ pthread_mutex_unlock( &__THREAD_NAME(name)._private_lock ) -__LIBC_HIDDEN__ void _thread_atexit_lock(void); -__LIBC_HIDDEN__ void _thread_atexit_unlock(void); +/* Note that these aren't compatible with the usual OpenBSD ones which lazy-initialize! */ +#define _MUTEX_LOCK(l) pthread_mutex_lock((pthread_mutex_t*) l) +#define _MUTEX_UNLOCK(l) pthread_mutex_unlock((pthread_mutex_t*) l) + +__LIBC_HIDDEN__ void _thread_atexit_lock(void); +__LIBC_HIDDEN__ void _thread_atexit_unlock(void); #define _ATEXIT_LOCK() _thread_atexit_lock() #define _ATEXIT_UNLOCK() _thread_atexit_unlock() diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h index f00d91a..cf63907 100644 --- a/libc/upstream-openbsd/android/include/openbsd-compat.h +++ b/libc/upstream-openbsd/android/include/openbsd-compat.h @@ -40,4 +40,6 @@ __LIBC64_HIDDEN__ extern const short *_tolower_tab_; __LIBC64_HIDDEN__ extern const short *_toupper_tab_; +__LIBC_HIDDEN__ extern struct atexit *__atexit; + #endif diff --git a/libc/upstream-openbsd/android/include/thread_private.h b/libc/upstream-openbsd/android/include/thread_private.h deleted file mode 100644 index 10421e2..0000000 --- a/libc/upstream-openbsd/android/include/thread_private.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _THREAD_PRIVATE_H_ -#define _THREAD_PRIVATE_H_ - -#include <pthread.h> - -/* Note that these aren't compatible with the usual OpenBSD ones which lazy-initialize! */ -#define _MUTEX_LOCK(l) pthread_mutex_lock((pthread_mutex_t*) l) -#define _MUTEX_UNLOCK(l) pthread_mutex_unlock((pthread_mutex_t*) l) - -#endif /* _THREAD_PRIVATE_H_ */ diff --git a/libc/stdlib/atexit.c b/libc/upstream-openbsd/lib/libc/stdlib/atexit.c index e10238b..6532b38 100644 --- a/libc/stdlib/atexit.c +++ b/libc/upstream-openbsd/lib/libc/stdlib/atexit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: atexit.c,v 1.14 2007/09/05 20:47:47 chl Exp $ */ +/* $OpenBSD: atexit.c,v 1.20 2014/07/11 09:51:37 kettenis Exp $ */ /* * Copyright (c) 2002 Daniel Hartmeier * All rights reserved. @@ -35,57 +35,16 @@ #include <string.h> #include <unistd.h> #include "atexit.h" -#include "private/thread_private.h" +#include "thread_private.h" struct atexit *__atexit; - -/* - * TODO: Read this before upstreaming: - * - * As of Apr 2014 there is a bug regaring function type detection logic in - * Free/Open/NetBSD implementations of __cxa_finalize(). - * - * What it is about: - * First of all there are two kind of atexit handlers: - * 1) void handler(void) - this is the regular type - * available for to user via atexit(.) function call. - * - * 2) void internal_handler(void*) - this is the type - * __cxa_atexit() function expects. This handler is used - * by C++ compiler to register static destructor calls. - * Note that calling this function as the handler of type (1) - * results in incorrect this pointer in static d-tors. - * - * What is wrong with BSD implementations: - * - * They use dso argument to identify the handler type. The problem - * with it is dso is also used to identify the handlers associated - * with particular dynamic library and allow __cxa_finalize to call correct - * set of functions on dlclose(). And it cannot identify both. - * - * What is correct way to identify function type? - * - * Consider this: - * 1. __cxa_finalize and __cxa_atexit are part of libc and do not have access to hidden - * &__dso_handle. - * 2. __cxa_atexit has only 3 arguments: function pointer, function argument, dso. - * none of them can be reliably used to pass information about handler type. - * 3. following http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor (3.3.5.3 - B) - * translation of user atexit -> __cxa_atexit(f, NULL, NULL) results in crashes - * on exit() after dlclose() of a library with an atexit() call. - * - * One way to resolve this is to always call second form of handler, which will - * result in storing unused argument in register/stack depending on architecture - * and should not present any problems. - * - * Another way is to make them dso-local in one way or the other. - */ +static int restartloop; /* * Function pointers are stored in a linked list of pages. The list * is initially empty, and pages are allocated on demand. The first * function pointer in the first allocated page (the last one in - * the linked list) was reserved for the cleanup function. + * the linked list) is reserved for the cleanup function. * * Outside the following functions, all pages are mprotect()'ed * to prevent unintentional/malicious corruption. @@ -103,7 +62,7 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso) { struct atexit *p = __atexit; struct atexit_fn *fnp; - size_t pgsize = getpagesize(); + int pgsize = getpagesize(); int ret = -1; if (pgsize < sizeof(*p)) @@ -132,11 +91,12 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso) __atexit = p; } fnp = &p->fns[p->ind++]; - fnp->cxa_func = func; + fnp->fn_ptr = func; fnp->fn_arg = arg; fnp->fn_dso = dso; if (mprotect(p, pgsize, PROT_READ)) goto unlock; + restartloop = 1; ret = 0; unlock: _ATEXIT_UNLOCK(); @@ -151,50 +111,41 @@ unlock: void __cxa_finalize(void *dso) { - struct atexit *p, *q, *original_atexit; + struct atexit *p, *q; struct atexit_fn fn; - int n, pgsize = getpagesize(), original_ind; + int n, pgsize = getpagesize(); static int call_depth; _ATEXIT_LOCK(); call_depth++; - p = original_atexit = __atexit; - n = original_ind = p != NULL ? p->ind : 0; - while (p != NULL) { - if (p->fns[n].cxa_func != NULL /* not called */ - && (dso == NULL || dso == p->fns[n].fn_dso)) { /* correct DSO */ +restart: + restartloop = 0; + for (p = __atexit; p != NULL; p = p->next) { + for (n = p->ind; --n >= 0;) { + if (p->fns[n].fn_ptr == NULL) + continue; /* already called */ + if (dso != NULL && dso != p->fns[n].fn_dso) + continue; /* wrong DSO */ + /* * Mark handler as having been already called to avoid * dupes and loops, then call the appropriate function. */ fn = p->fns[n]; if (mprotect(p, pgsize, PROT_READ | PROT_WRITE) == 0) { - p->fns[n].cxa_func = NULL; + p->fns[n].fn_ptr = NULL; mprotect(p, pgsize, PROT_READ); } - _ATEXIT_UNLOCK(); - (*fn.cxa_func)(fn.fn_arg); + (*fn.fn_ptr)(fn.fn_arg); _ATEXIT_LOCK(); - // check for new atexit handlers - if ((__atexit->ind != original_ind) || (__atexit != original_atexit)) { - // need to restart now to preserve correct - // call order - LIFO - p = original_atexit = __atexit; - n = original_ind = p->ind; - continue; - } - } - if (n == 0) { - p = p->next; - n = p != NULL ? p->ind : 0; - } else { - --n; + if (restartloop) + goto restart; } } - --call_depth; + call_depth--; /* * If called via exit(), unmap the pages since we have now run @@ -218,33 +169,34 @@ __cxa_finalize(void *dso) void __atexit_register_cleanup(void (*func)(void)) { - struct atexit *p; - size_t pgsize = getpagesize(); + struct atexit *p; + int pgsize = getpagesize(); - if (pgsize < sizeof(*p)) - return; - _ATEXIT_LOCK(); - p = __atexit; - while (p != NULL && p->next != NULL) - p = p->next; - if (p == NULL) { - p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); - if (p == MAP_FAILED) - goto unlock; - p->ind = 1; - p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) / - sizeof(p->fns[0]); - p->next = NULL; - __atexit = p; - } else { - if (mprotect(p, pgsize, PROT_READ | PROT_WRITE)) - goto unlock; - } - p->fns[0].cxa_func = (void (*)(void*))func; - p->fns[0].fn_arg = NULL; - p->fns[0].fn_dso = NULL; - mprotect(p, pgsize, PROT_READ); + if (pgsize < sizeof(*p)) + return; + _ATEXIT_LOCK(); + p = __atexit; + while (p != NULL && p->next != NULL) + p = p->next; + if (p == NULL) { + p = mmap(NULL, pgsize, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) + goto unlock; + p->ind = 1; + p->max = (pgsize - ((char *)&p->fns[0] - (char *)p)) / + sizeof(p->fns[0]); + p->next = NULL; + __atexit = p; + } else { + if (mprotect(p, pgsize, PROT_READ | PROT_WRITE)) + goto unlock; + } + p->fns[0].fn_ptr = (void (*)(void *))func; + p->fns[0].fn_arg = NULL; + p->fns[0].fn_dso = NULL; + mprotect(p, pgsize, PROT_READ); + restartloop = 1; unlock: - _ATEXIT_UNLOCK(); + _ATEXIT_UNLOCK(); } diff --git a/libc/stdlib/atexit.h b/libc/upstream-openbsd/lib/libc/stdlib/atexit.h index b530ade..3de2aa3 100644 --- a/libc/stdlib/atexit.h +++ b/libc/upstream-openbsd/lib/libc/stdlib/atexit.h @@ -1,4 +1,4 @@ -/* $OpenBSD: atexit.h,v 1.7 2007/09/03 14:40:16 millert Exp $ */ +/* $OpenBSD: atexit.h,v 1.9 2014/06/18 19:01:10 kettenis Exp $ */ /* * Copyright (c) 2002 Daniel Hartmeier @@ -30,24 +30,18 @@ * */ -#include <sys/cdefs.h> - struct atexit { struct atexit *next; /* next in list */ int ind; /* next index in this table */ int max; /* max entries >= ATEXIT_SIZE */ struct atexit_fn { - void (*cxa_func)(void *); + void (*fn_ptr)(void *); void *fn_arg; /* argument for CXA callback */ void *fn_dso; /* shared module handle */ } fns[1]; /* the table itself */ }; -__BEGIN_DECLS - -__LIBC_HIDDEN__ extern struct atexit *__atexit; /* points to head of LIFO stack */ +extern struct atexit *__atexit; /* points to head of LIFO stack */ int __cxa_atexit(void (*)(void *), void *, void *); void __cxa_finalize(void *); - -__END_DECLS |