forked from OSchip/llvm-project
tsan: do not call into libc in symbolizer and in other code (this causes recursion and crashes)
llvm-svn: 157466
This commit is contained in:
parent
e86497ee1c
commit
7339eb197b
|
@ -169,6 +169,7 @@ uptr internal_strlen(const char *s);
|
|||
char* internal_strdup(const char *s);
|
||||
const char *internal_strstr(const char *where, const char *what);
|
||||
const char *internal_strchr(const char *where, char what);
|
||||
const char *internal_strrchr(const char *where, char what);
|
||||
|
||||
struct MD5Hash {
|
||||
u64 hash[2];
|
||||
|
|
|
@ -138,10 +138,7 @@ class ScopedInterceptor {
|
|||
/**/
|
||||
|
||||
#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
|
||||
#define TSAN_INTERCEPT(func) \
|
||||
if (!INTERCEPT_FUNCTION(func) && flags()->verbosity) \
|
||||
Printf("ThreadSanitizer: failed to intercept '" #func "' function\n"); \
|
||||
/**/
|
||||
#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
|
||||
|
||||
// May be overriden by front-end.
|
||||
extern "C" void WEAK __tsan_malloc_hook(void *ptr, uptr size) {
|
||||
|
@ -1551,6 +1548,10 @@ const char *internal_strchr(const char *where, char what) {
|
|||
return (const char*)REAL(strchr)((void*)where, what);
|
||||
}
|
||||
|
||||
const char *internal_strrchr(const char *where, char what) {
|
||||
return (const char*)REAL(strrchr)((void*)where, what);
|
||||
}
|
||||
|
||||
void internal_start_thread(void(*func)(void *arg), void *arg) {
|
||||
void *th;
|
||||
REAL(pthread_create)(&th, 0, (void*(*)(void *arg))func, arg);
|
||||
|
|
|
@ -83,10 +83,11 @@ void internal_close(fd_t fd);
|
|||
uptr internal_filesize(fd_t fd); // -1 on error.
|
||||
uptr internal_read(fd_t fd, void *p, uptr size);
|
||||
uptr internal_write(fd_t fd, const void *p, uptr size);
|
||||
int internal_dup2(int oldfd, int newfd);
|
||||
const char *internal_getpwd();
|
||||
|
||||
uptr GetTlsSize();
|
||||
void GetThreadStackAndTls(uptr *stk_addr, uptr *stk_size,
|
||||
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
||||
uptr *tls_addr, uptr *tls_size);
|
||||
|
||||
} // namespace __tsan
|
||||
|
|
|
@ -79,6 +79,11 @@ static void *my_mmap(void *addr, size_t length, int prot, int flags,
|
|||
# endif
|
||||
}
|
||||
|
||||
static void my_munmap(void *addr, size_t length) {
|
||||
ScopedInRtl in_rtl;
|
||||
syscall(__NR_munmap, addr, length);
|
||||
}
|
||||
|
||||
void internal_yield() {
|
||||
ScopedInRtl in_rtl;
|
||||
syscall(__NR_sched_yield);
|
||||
|
@ -116,6 +121,11 @@ uptr internal_write(fd_t fd, const void *p, uptr size) {
|
|||
return syscall(__NR_write, fd, p, size);
|
||||
}
|
||||
|
||||
int internal_dup2(int oldfd, int newfd) {
|
||||
ScopedInRtl in_rtl;
|
||||
return syscall(__NR_dup2, oldfd, newfd);
|
||||
}
|
||||
|
||||
const char *internal_getpwd() {
|
||||
return getenv("PWD");
|
||||
}
|
||||
|
@ -230,25 +240,75 @@ uptr GetTlsSize() {
|
|||
return g_tls_size;
|
||||
}
|
||||
|
||||
void GetThreadStackAndTls(uptr *stk_addr, uptr *stk_size,
|
||||
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
||||
uptr *tls_addr, uptr *tls_size) {
|
||||
*stk_addr = 0;
|
||||
*stk_size = 0;
|
||||
pthread_attr_t attr;
|
||||
if (pthread_getattr_np(pthread_self(), &attr) == 0) {
|
||||
pthread_attr_getstack(&attr, (void**)stk_addr, (size_t*)stk_size);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
arch_prctl(ARCH_GET_FS, tls_addr);
|
||||
*tls_addr -= g_tls_size;
|
||||
*tls_size = g_tls_size;
|
||||
|
||||
// If stack and tls intersect, make them non-intersecting.
|
||||
if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
|
||||
CHECK_GT(*tls_addr + *tls_size, *stk_addr);
|
||||
CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
|
||||
*stk_size -= *tls_size;
|
||||
*tls_addr = *stk_addr + *stk_size;
|
||||
if (main) {
|
||||
uptr kBufSize = 1 << 20;
|
||||
char *buf = (char*)my_mmap(0, kBufSize, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
fd_t maps = internal_open("/proc/self/maps", false);
|
||||
if (maps == kInvalidFd) {
|
||||
Printf("Failed to open /proc/self/maps\n");
|
||||
Die();
|
||||
}
|
||||
char *end = buf;
|
||||
while (end + kPageSize < buf + kBufSize) {
|
||||
uptr read = internal_read(maps, end, kPageSize);
|
||||
if ((int)read <= 0)
|
||||
break;
|
||||
end += read;
|
||||
}
|
||||
end[0] = 0;
|
||||
end = (char*)internal_strstr(buf, "[stack]");
|
||||
if (end == 0) {
|
||||
Printf("Can't find [stack] in /proc/self/maps\n");
|
||||
Die();
|
||||
}
|
||||
end[0] = 0;
|
||||
char *pos = (char*)internal_strrchr(buf, '\n');
|
||||
if (pos == 0) {
|
||||
Printf("Can't find [stack] in /proc/self/maps\n");
|
||||
Die();
|
||||
}
|
||||
uptr stack = 0;
|
||||
for (; pos++;) {
|
||||
uptr num = 0;
|
||||
if (pos[0] >= '0' && pos[0] <= '9')
|
||||
num = pos[0] - '0';
|
||||
else if (pos[0] >= 'a' && pos[0] <= 'f')
|
||||
num = pos[0] - 'a' + 10;
|
||||
else
|
||||
break;
|
||||
stack = stack * 16 + num;
|
||||
}
|
||||
internal_close(maps);
|
||||
my_munmap(buf, kBufSize);
|
||||
|
||||
struct rlimit rl;
|
||||
CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
|
||||
|
||||
*stk_addr = stack;
|
||||
*stk_size = rl.rlim_cur;
|
||||
} else {
|
||||
*stk_addr = 0;
|
||||
*stk_size = 0;
|
||||
pthread_attr_t attr;
|
||||
if (pthread_getattr_np(pthread_self(), &attr) == 0) {
|
||||
pthread_attr_getstack(&attr, (void**)stk_addr, (size_t*)stk_size);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
|
||||
// If stack and tls intersect, make them non-intersecting.
|
||||
if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
|
||||
CHECK_GT(*tls_addr + *tls_size, *stk_addr);
|
||||
CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
|
||||
*stk_size -= *tls_size;
|
||||
*tls_addr = *stk_addr + *stk_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ void ThreadStart(ThreadState *thr, int tid) {
|
|||
uptr stk_size = 0;
|
||||
uptr tls_addr = 0;
|
||||
uptr tls_size = 0;
|
||||
GetThreadStackAndTls(&stk_addr, &stk_size, &tls_addr, &tls_size);
|
||||
GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
|
||||
|
||||
MemoryResetRange(thr, /*pc=*/ 1, stk_addr, stk_size);
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <link.h>
|
||||
#include <linux/limits.h>
|
||||
|
@ -59,22 +58,23 @@ static void NOINLINE InitModule(ModuleDesc *m) {
|
|||
}
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
close(STDOUT_FILENO);
|
||||
close(STDIN_FILENO);
|
||||
dup2(outfd[0], STDIN_FILENO);
|
||||
dup2(infd[1], STDOUT_FILENO);
|
||||
close(outfd[0]);
|
||||
close(outfd[1]);
|
||||
close(infd[0]);
|
||||
close(infd[1]);
|
||||
flags()->log_fileno = STDERR_FILENO;
|
||||
internal_close(STDOUT_FILENO);
|
||||
internal_close(STDIN_FILENO);
|
||||
internal_dup2(outfd[0], STDIN_FILENO);
|
||||
internal_dup2(infd[1], STDOUT_FILENO);
|
||||
internal_close(outfd[0]);
|
||||
internal_close(outfd[1]);
|
||||
internal_close(infd[0]);
|
||||
internal_close(infd[1]);
|
||||
execl("/usr/bin/addr2line", "/usr/bin/addr2line", "-Cfe", m->fullname, 0);
|
||||
_exit(0);
|
||||
} else if (pid < 0) {
|
||||
Printf("ThreadSanitizer: failed to fork symbolizer\n");
|
||||
Die();
|
||||
}
|
||||
close(outfd[0]);
|
||||
close(infd[1]);
|
||||
internal_close(outfd[0]);
|
||||
internal_close(infd[1]);
|
||||
m->inp_fd = infd[0];
|
||||
m->out_fd = outfd[1];
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
|
|||
ModuleDesc *m = (ModuleDesc*)internal_alloc(MBlockReportStack,
|
||||
sizeof(ModuleDesc));
|
||||
m->fullname = internal_strdup(info->dlpi_name);
|
||||
m->name = strrchr(m->fullname, '/'); // FIXME: internal_strrchr
|
||||
m->name = internal_strrchr(m->fullname, '/');
|
||||
if (m->name)
|
||||
m->name += 1;
|
||||
else
|
||||
|
@ -173,12 +173,12 @@ ReportStack *SymbolizeCode(uptr addr) {
|
|||
ReportStack *res = NewFrame(addr);
|
||||
res->module = internal_strdup(m->name);
|
||||
res->offset = offset;
|
||||
char *pos = strchr(func, '\n');
|
||||
char *pos = (char*)internal_strchr(func, '\n');
|
||||
if (pos && func[0] != '?') {
|
||||
res->func = (char*)internal_alloc(MBlockReportStack, pos - func + 1);
|
||||
internal_memcpy(res->func, func, pos - func);
|
||||
res->func[pos - func] = 0;
|
||||
char *pos2 = strchr(pos, ':');
|
||||
char *pos2 = (char*)internal_strchr(pos, ':');
|
||||
if (pos2) {
|
||||
res->file = (char*)internal_alloc(MBlockReportStack, pos2 - pos - 1 + 1);
|
||||
internal_memcpy(res->file, pos + 1, pos2 - pos - 1);
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
|
||||
namespace __tsan {
|
||||
|
||||
static void *TestThreadInfo(void *arg) {
|
||||
static void TestThreadInfo(bool main) {
|
||||
ScopedInRtl in_rtl;
|
||||
uptr stk_addr = 0;
|
||||
uptr stk_size = 0;
|
||||
uptr tls_addr = 0;
|
||||
uptr tls_size = 0;
|
||||
GetThreadStackAndTls(&stk_addr, &stk_size, &tls_addr, &tls_size);
|
||||
GetThreadStackAndTls(main, &stk_addr, &stk_size, &tls_addr, &tls_size);
|
||||
// Printf("stk=%lx-%lx(%lu)\n", stk_addr, stk_addr + stk_size, stk_size);
|
||||
// Printf("tls=%lx-%lx(%lu)\n", tls_addr, tls_addr + tls_size, tls_size);
|
||||
|
||||
|
@ -42,16 +42,20 @@ static void *TestThreadInfo(void *arg) {
|
|||
EXPECT_TRUE(tls_addr < stk_addr || tls_addr >= stk_addr + stk_size);
|
||||
EXPECT_TRUE(tls_end < stk_addr || tls_end >= stk_addr + stk_size);
|
||||
EXPECT_TRUE((tls_addr < stk_addr) == (tls_end < stk_addr));
|
||||
}
|
||||
|
||||
static void *WorkerThread(void *arg) {
|
||||
TestThreadInfo(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(Platform, ThreadInfoMain) {
|
||||
TestThreadInfo(0);
|
||||
TestThreadInfo(true);
|
||||
}
|
||||
|
||||
TEST(Platform, ThreadInfoWorker) {
|
||||
pthread_t t;
|
||||
pthread_create(&t, 0, TestThreadInfo, 0);
|
||||
pthread_create(&t, 0, WorkerThread, 0);
|
||||
pthread_join(t, 0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue