Last active
August 29, 2015 14:07
-
-
Save kevinlynx/69435e718785a0ad12c4 to your computer and use it in GitHub Desktop.
thread-tls-bug https://sourceware.org/bugzilla/show_bug.cgi?id=13862
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: | |
g++ -o thread -g -Wall -lpthread -ldl thread.cpp -DTEST_DTV_OVERFLOW | |
g++ -rdynamic -shared -fPIC dso_shared.cc -o shared.so | |
mkdir -p so | |
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19; do cp shared.so so/shared-$$i.so; done | |
clean: | |
rm *.so so/*.so |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
dtv overflow bug in glibc: | |
1. create a thread and the thread exit | |
2. load more than 16 modules (*.so) with tls variables | |
3. create a new thread | |
*/ | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <dlfcn.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <pthread.h> | |
#ifndef SO_CNT | |
#define SO_CNT 19 | |
#endif | |
typedef void (*function)(); | |
void *gso = 0; | |
union dtv_t { | |
size_t counter; | |
struct { | |
void *val; /* point to tls variable memory */ | |
bool is_static; | |
} pointer; | |
}; | |
struct tcbhead_t { | |
void *tcb; | |
dtv_t *dtv; /* point to a dtv_t array */ | |
void *padding[22]; /* other members i don't care */ | |
}; | |
struct pthread { | |
tcbhead_t tcb; | |
/* more members i don't care */ | |
}; | |
void dump_pthread(pthread_t id) { | |
pthread *pd = (pthread*) id; | |
dtv_t *dtv = pd->tcb.dtv; | |
printf("pthread %p, dtv %p\n", pd, dtv); | |
} | |
void load_sos() { | |
/* more than default dtv array size, will create a new expanded dtv */ | |
void *lso[SO_CNT]; | |
for (int i = 0; i < SO_CNT; ++i) { | |
char path[32]; | |
sprintf(path, "so/shared-%d.so", i); | |
lso[i] = dlopen(path, RTLD_NOW); | |
function fn = (function)dlsym(lso[i], "function"); | |
fn(); | |
} | |
pthread_t tid = pthread_self(); | |
dump_pthread(tid); | |
for (int i = 0; i < SO_CNT; ++i) { | |
dlclose(lso[i]); | |
} | |
} | |
void *thread_func(void *) { | |
pthread_t tid = pthread_self(); | |
fprintf(stderr, "thread %x\n", (unsigned) tid); | |
dump_pthread(tid); | |
function fn = (function)dlsym(gso, "function"); | |
fn(); | |
#ifdef TEST_DTV_EXPAND | |
load_sos(); | |
#endif | |
return 0; | |
} | |
void spawn_thread() { | |
pthread_t tid; | |
pthread_create(&tid, 0, thread_func, 0); | |
pthread_join(tid, NULL); | |
#ifdef TEST_CACHE_STACK | |
/* new thread will reuse the cache stack, including dtv */ | |
pthread_create(&tid, 0, thread_func, 0); | |
pthread_join(tid, NULL); | |
#elif TEST_DTV_INC | |
/* load 1 so, check dtv[4] */ | |
void *so = dlopen("so/shared-0.so", RTLD_NOW); | |
function fn = (function)dlsym(so, "function"); | |
fn(); | |
pthread_create(&tid, 0, thread_func, 0); | |
pthread_join(tid, NULL); | |
dlclose(so); | |
#elif TEST_DTV_OVERFLOW /* coredump because dtv array overflow */ | |
/* load more tls modules, `get_cached_stack` -> `_dl_allocate_tls_init` */ | |
/* dtv array size 17, dtv will overflow if SO_CNT > 14 */ | |
void *lso[SO_CNT]; | |
for (int i = 0; i < SO_CNT; ++i) { | |
char path[32]; | |
sprintf(path, "so/shared-%d.so", i); | |
lso[i] = dlopen(path, RTLD_NOW); | |
function fn = (function)dlsym(lso[i], "function"); | |
fn(); | |
} | |
pthread_create(&tid, 0, thread_func, 0); | |
pthread_join(tid, NULL); | |
for (int i = 0; i < SO_CNT; ++i) { | |
dlclose(lso[i]); | |
} | |
#endif | |
} | |
int main() { | |
gso = dlopen("shared.so", RTLD_NOW); | |
spawn_thread(); | |
dlclose(gso); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment