1303795Skib/*- 2303795Skib * Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com> 3311651Skib * Copyright (c) 2016, 2017 The FreeBSD Foundation 4303795Skib * All rights reserved. 5303795Skib * 6311651Skib * Portions of this software were developed by Konstantin Belousov 7311651Skib * under sponsorship from the FreeBSD Foundation. 8311651Skib * 9303795Skib * Redistribution and use in source and binary forms, with or without 10303795Skib * modification, are permitted provided that the following conditions 11303795Skib * are met: 12303795Skib * 1. Redistributions of source code must retain the above copyright 13303795Skib * notice, this list of conditions and the following disclaimer. 14303795Skib * 2. Redistributions in binary form must reproduce the above copyright 15303795Skib * notice, this list of conditions and the following disclaimer in the 16303795Skib * documentation and/or other materials provided with the distribution. 17303795Skib * 18303795Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19303795Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20303795Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21303795Skib * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22303795Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23303795Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24303795Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25303795Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26303795Skib * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27303795Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28303795Skib * SUCH DAMAGE. 29303795Skib */ 30303795Skib 31303795Skib#include <sys/cdefs.h> 32303795Skib__FBSDID("$FreeBSD: stable/10/lib/libc/stdlib/cxa_thread_atexit_impl.c 312590 2017-01-21 12:30:07Z kib $"); 33303795Skib 34303795Skib#include <sys/queue.h> 35303795Skib#include "namespace.h" 36303795Skib#include <errno.h> 37303795Skib#include <link.h> 38303795Skib#include <pthread.h> 39303795Skib#include <stddef.h> 40303795Skib#include <stdlib.h> 41303795Skib#include <stdio.h> 42303795Skib#include "un-namespace.h" 43303795Skib#include "libc_private.h" 44303795Skib 45303795Skib/* 46303795Skib * C++11 introduces the thread_local scope (like __thread with some 47303795Skib * additions). As a key-feature it should support non-trivial 48303795Skib * destructors, registered with __cxa_thread_atexit() to be executed 49303795Skib * at the thread termination. 50303795Skib * 51303795Skib * The implemention keeps a _Thread_local list of destructors per each 52303795Skib * thread, and calls __cxa_thread_call_dtors() on each thread's exit 53303795Skib * to do cleanup. For a thread calling exit(3), in particular, for 54303795Skib * the initial thread returning from main(), we call 55303795Skib * __cxa_thread_call_dtors() inside exit(). 56303795Skib * 57303795Skib * It could be possible that a dynamically loaded library, use 58303795Skib * thread_local variable but is dlclose()'d before thread exit. The 59303795Skib * destructor of this variable will then try to access the address, 60303795Skib * for calling it but it's unloaded, so it'll crash. We're using 61303795Skib * __elf_phdr_match_addr() to detect and prevent such cases and so 62303795Skib * prevent the crash. 63303795Skib */ 64303795Skib 65303795Skib#define CXA_DTORS_ITERATIONS 4 66303795Skib 67303795Skibstruct cxa_thread_dtor { 68303795Skib void *obj; 69303795Skib void (*func)(void *); 70303795Skib void *dso; 71303795Skib LIST_ENTRY(cxa_thread_dtor) entry; 72303795Skib}; 73303795Skibstatic _Thread_local LIST_HEAD(dtor_list, cxa_thread_dtor) dtors = 74303795Skib LIST_HEAD_INITIALIZER(dtors); 75303795Skib 76303795Skibint 77311651Skib__cxa_thread_atexit_impl(void (*dtor_func)(void *), void *obj, 78311651Skib void *dso_symbol) 79303795Skib{ 80311651Skib 81311651Skib return (__cxa_thread_atexit_hidden(dtor_func, obj, dso_symbol)); 82311651Skib} 83311651Skib 84311651Skibint 85311651Skib__cxa_thread_atexit_hidden(void (*dtor_func)(void *), void *obj, 86311651Skib void *dso_symbol) 87311651Skib{ 88303795Skib struct cxa_thread_dtor *new_dtor; 89303795Skib 90303795Skib new_dtor = malloc(sizeof(*new_dtor)); 91303795Skib if (new_dtor == NULL) { 92303795Skib errno = ENOMEM; /* forcibly override malloc(3) error */ 93303795Skib return (-1); 94303795Skib } 95303795Skib 96303795Skib new_dtor->obj = obj; 97303795Skib new_dtor->func = dtor_func; 98303795Skib new_dtor->dso = dso_symbol; 99303795Skib LIST_INSERT_HEAD(&dtors, new_dtor, entry); 100303795Skib return (0); 101303795Skib} 102303795Skib 103303795Skibstatic void 104303795Skibwalk_cb_call(struct cxa_thread_dtor *dtor) 105303795Skib{ 106303795Skib struct dl_phdr_info phdr_info; 107303795Skib 108303795Skib if (_rtld_addr_phdr(dtor->dso, &phdr_info) && 109303795Skib __elf_phdr_match_addr(&phdr_info, dtor->func)) 110303795Skib dtor->func(dtor->obj); 111303795Skib else 112303795Skib fprintf(stderr, "__cxa_thread_call_dtors: dtr %p from " 113303795Skib "unloaded dso, skipping\n", (void *)(dtor->func)); 114303795Skib} 115303795Skib 116303795Skibstatic void 117303795Skibwalk_cb_nocall(struct cxa_thread_dtor *dtor __unused) 118303795Skib{ 119303795Skib} 120303795Skib 121303795Skibstatic void 122303795Skibcxa_thread_walk(void (*cb)(struct cxa_thread_dtor *)) 123303795Skib{ 124303795Skib struct cxa_thread_dtor *dtor, *tdtor; 125303795Skib 126303795Skib LIST_FOREACH_SAFE(dtor, &dtors, entry, tdtor) { 127303795Skib LIST_REMOVE(dtor, entry); 128303795Skib cb(dtor); 129303795Skib free(dtor); 130303795Skib } 131303795Skib} 132303795Skib 133303795Skib/* 134303795Skib * This is the callback function we use to call destructors, once for 135303795Skib * each thread. It is called in exit(3) in libc/stdlib/exit.c and 136303795Skib * before exit_thread() in libthr/thread/thr_exit.c. 137303795Skib */ 138303795Skibvoid 139303795Skib__cxa_thread_call_dtors(void) 140303795Skib{ 141303795Skib int i; 142303795Skib 143303795Skib for (i = 0; i < CXA_DTORS_ITERATIONS && !LIST_EMPTY(&dtors); i++) 144303795Skib cxa_thread_walk(walk_cb_call); 145303795Skib 146303795Skib if (!LIST_EMPTY(&dtors)) { 147303795Skib fprintf(stderr, "Thread %p is exiting with more " 148303795Skib "thread-specific dtors created after %d iterations " 149303795Skib "of destructor calls\n", 150303795Skib _pthread_self(), i); 151303795Skib cxa_thread_walk(walk_cb_nocall); 152303795Skib } 153303795Skib} 154