Skip to content

Instantly share code, notes, and snippets.

@kevinlynx
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevinlynx/69435e718785a0ad12c4 to your computer and use it in GitHub Desktop.
Save kevinlynx/69435e718785a0ad12c4 to your computer and use it in GitHub Desktop.
#include <stdio.h>
static __thread int c = 0x55667788;
extern "C" void function(void)
{
/*
static __thread int var[256] = {0};
for (int i = 0; i < 256; i++)
var[i] = i; */
static __thread int a = 0x11223344;
static __thread int b = 0xaabbccdd;
printf("%p, %p, %p\n", &a, &b, &c);
}
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
/*
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