This adds support for TSan C++ exception handling, where we need to add extra calls to __tsan_func_exit when a function is exitted via exception mechanisms. Otherwise the shadow stack gets corrupted (leaked). This patch moves and enhances the existing implementation of EscapeEnumerator that finds all possible function exit points, and adds extra EH cleanup blocks where needed. Differential Revision: https://reviews.llvm.org/D26177 llvm-svn: 286894
90 lines
2.6 KiB
C
90 lines
2.6 KiB
C
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <dlfcn.h>
|
|
#include <stddef.h>
|
|
#include <sched.h>
|
|
#include <stdarg.h>
|
|
#include "sanitizer_common/print_address.h"
|
|
|
|
#ifdef __APPLE__
|
|
#include <mach/mach_time.h>
|
|
#endif
|
|
|
|
// TSan-invisible barrier.
|
|
// Tests use it to establish necessary execution order in a way that does not
|
|
// interfere with tsan (does not establish synchronization between threads).
|
|
typedef unsigned long long invisible_barrier_t;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
void __tsan_testonly_barrier_init(invisible_barrier_t *barrier,
|
|
unsigned count);
|
|
void __tsan_testonly_barrier_wait(invisible_barrier_t *barrier);
|
|
unsigned long __tsan_testonly_shadow_stack_current_size();
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
static inline void barrier_init(invisible_barrier_t *barrier, unsigned count) {
|
|
__tsan_testonly_barrier_init(barrier, count);
|
|
}
|
|
|
|
static inline void barrier_wait(invisible_barrier_t *barrier) {
|
|
__tsan_testonly_barrier_wait(barrier);
|
|
}
|
|
|
|
// Default instance of the barrier, but a test can declare more manually.
|
|
invisible_barrier_t barrier;
|
|
|
|
#ifdef __APPLE__
|
|
unsigned long long monotonic_clock_ns() {
|
|
static mach_timebase_info_data_t timebase_info;
|
|
if (timebase_info.denom == 0) mach_timebase_info(&timebase_info);
|
|
return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom;
|
|
}
|
|
#else
|
|
unsigned long long monotonic_clock_ns() {
|
|
struct timespec t;
|
|
clock_gettime(CLOCK_MONOTONIC, &t);
|
|
return (unsigned long long)t.tv_sec * 1000000000ull + t.tv_nsec;
|
|
}
|
|
#endif
|
|
|
|
//The const kPCInc must be in sync with StackTrace::GetPreviousInstructionPc
|
|
#if defined(__powerpc64__)
|
|
// PCs are always 4 byte aligned.
|
|
const int kPCInc = 4;
|
|
#elif defined(__sparc__) || defined(__mips__)
|
|
const int kPCInc = 8;
|
|
#else
|
|
const int kPCInc = 1;
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
void AnnotateRWLockCreate(const char *f, int l, void *m);
|
|
void AnnotateRWLockCreateStatic(const char *f, int l, void *m);
|
|
void AnnotateRWLockDestroy(const char *f, int l, void *m);
|
|
void AnnotateRWLockAcquired(const char *f, int l, void *m, long is_w);
|
|
void AnnotateRWLockReleased(const char *f, int l, void *m, long is_w);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#define ANNOTATE_RWLOCK_CREATE(m) \
|
|
AnnotateRWLockCreate(__FILE__, __LINE__, m)
|
|
#define ANNOTATE_RWLOCK_CREATE_STATIC(m) \
|
|
AnnotateRWLockCreateStatic(__FILE__, __LINE__, m)
|
|
#define ANNOTATE_RWLOCK_DESTROY(m) \
|
|
AnnotateRWLockDestroy(__FILE__, __LINE__, m)
|
|
#define ANNOTATE_RWLOCK_ACQUIRED(m, is_w) \
|
|
AnnotateRWLockAcquired(__FILE__, __LINE__, m, is_w)
|
|
#define ANNOTATE_RWLOCK_RELEASED(m, is_w) \
|
|
AnnotateRWLockReleased(__FILE__, __LINE__, m, is_w)
|