forked from OSchip/llvm-project
[TSan] Provide replacements for operators new/delete instead of declaring extern C functions with weirdly mangled names (same strategy is used in ASan).
llvm-svn: 164487
This commit is contained in:
parent
a555b3faf4
commit
313014694f
|
@ -8,6 +8,7 @@ set(TSAN_SOURCES
|
|||
tsan_md5.cc
|
||||
tsan_mman.cc
|
||||
tsan_mutex.cc
|
||||
tsan_new_delete.cc
|
||||
tsan_printf.cc
|
||||
tsan_report.cc
|
||||
tsan_rtl.cc
|
||||
|
|
|
@ -42,6 +42,8 @@ LIBTSAN_OBJ=$(patsubst %.cc,%.o,$(LIBTSAN_SRC)) \
|
|||
|
||||
%_linux.o: %_linux.cc Makefile.old $(LIBTSAN_HEADERS)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $<
|
||||
%_new_delete.o: %_new_delete.cc Makefile.old $(LIBTSAN_HEADERS)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $<
|
||||
%.o: %.cc Makefile.old $(LIBTSAN_HEADERS)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) $(NO_SYSROOT) -c $<
|
||||
%.o: $(INTERCEPTION)/%.cc Makefile.old $(LIBTSAN_HEADERS)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===-- tsan_interceptors_linux.cc ----------------------------------------===//
|
||||
//===-- tsan_interceptors.cc ----------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -11,13 +11,13 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_placement_new.h"
|
||||
#include "tsan_rtl.h"
|
||||
#include "tsan_interceptors.h"
|
||||
#include "tsan_interface.h"
|
||||
#include "tsan_platform.h"
|
||||
#include "tsan_rtl.h"
|
||||
#include "tsan_mman.h"
|
||||
|
||||
using namespace __tsan; // NOLINT
|
||||
|
@ -133,89 +133,27 @@ static unsigned g_thread_finalize_key;
|
|||
|
||||
static void process_pending_signals(ThreadState *thr);
|
||||
|
||||
class ScopedInterceptor {
|
||||
public:
|
||||
ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc)
|
||||
: thr_(thr)
|
||||
, in_rtl_(thr->in_rtl) {
|
||||
if (thr_->in_rtl == 0) {
|
||||
Initialize(thr);
|
||||
FuncEntry(thr, pc);
|
||||
thr_->in_rtl++;
|
||||
DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
|
||||
} else {
|
||||
thr_->in_rtl++;
|
||||
}
|
||||
ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
|
||||
uptr pc)
|
||||
: thr_(thr)
|
||||
, in_rtl_(thr->in_rtl) {
|
||||
if (thr_->in_rtl == 0) {
|
||||
Initialize(thr);
|
||||
FuncEntry(thr, pc);
|
||||
thr_->in_rtl++;
|
||||
DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
|
||||
} else {
|
||||
thr_->in_rtl++;
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedInterceptor() {
|
||||
thr_->in_rtl--;
|
||||
if (thr_->in_rtl == 0) {
|
||||
FuncExit(thr_);
|
||||
process_pending_signals(thr_);
|
||||
}
|
||||
CHECK_EQ(in_rtl_, thr_->in_rtl);
|
||||
ScopedInterceptor::~ScopedInterceptor() {
|
||||
thr_->in_rtl--;
|
||||
if (thr_->in_rtl == 0) {
|
||||
FuncExit(thr_);
|
||||
process_pending_signals(thr_);
|
||||
}
|
||||
|
||||
private:
|
||||
ThreadState *const thr_;
|
||||
const int in_rtl_;
|
||||
};
|
||||
|
||||
#define SCOPED_INTERCEPTOR_RAW(func, ...) \
|
||||
ThreadState *thr = cur_thread(); \
|
||||
StatInc(thr, StatInterceptor); \
|
||||
StatInc(thr, StatInt_##func); \
|
||||
ScopedInterceptor si(thr, #func, \
|
||||
(__sanitizer::uptr)__builtin_return_address(0)); \
|
||||
const uptr pc = (uptr)&func; \
|
||||
(void)pc; \
|
||||
/**/
|
||||
|
||||
#define SCOPED_TSAN_INTERCEPTOR(func, ...) \
|
||||
SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
|
||||
if (thr->in_rtl > 1) \
|
||||
return REAL(func)(__VA_ARGS__); \
|
||||
/**/
|
||||
|
||||
#define SCOPED_INTERCEPTOR_LIBC(func, ...) \
|
||||
ThreadState *thr = cur_thread(); \
|
||||
StatInc(thr, StatInterceptor); \
|
||||
StatInc(thr, StatInt_##func); \
|
||||
ScopedInterceptor si(thr, #func, callpc); \
|
||||
const uptr pc = (uptr)&func; \
|
||||
(void)pc; \
|
||||
if (thr->in_rtl > 1) \
|
||||
return REAL(func)(__VA_ARGS__); \
|
||||
/**/
|
||||
|
||||
#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
|
||||
#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
|
||||
|
||||
// May be overriden by front-end.
|
||||
extern "C" void WEAK __tsan_malloc_hook(void *ptr, uptr size) {
|
||||
(void)ptr;
|
||||
(void)size;
|
||||
}
|
||||
|
||||
extern "C" void WEAK __tsan_free_hook(void *ptr) {
|
||||
(void)ptr;
|
||||
}
|
||||
|
||||
static void invoke_malloc_hook(void *ptr, uptr size) {
|
||||
Context *ctx = CTX();
|
||||
ThreadState *thr = cur_thread();
|
||||
if (ctx == 0 || !ctx->initialized || thr->in_rtl)
|
||||
return;
|
||||
__tsan_malloc_hook(ptr, size);
|
||||
}
|
||||
|
||||
static void invoke_free_hook(void *ptr) {
|
||||
Context *ctx = CTX();
|
||||
ThreadState *thr = cur_thread();
|
||||
if (ctx == 0 || !ctx->initialized || thr->in_rtl)
|
||||
return;
|
||||
__tsan_free_hook(ptr);
|
||||
CHECK_EQ(in_rtl_, thr_->in_rtl);
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) {
|
||||
|
@ -562,92 +500,6 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
|
|||
return res;
|
||||
}
|
||||
|
||||
#ifdef __LP64__
|
||||
|
||||
// void *operator new(size_t)
|
||||
TSAN_INTERCEPTOR(void*, _Znwm, uptr sz) {
|
||||
void *p = 0;
|
||||
{
|
||||
SCOPED_TSAN_INTERCEPTOR(_Znwm, sz);
|
||||
p = user_alloc(thr, pc, sz);
|
||||
}
|
||||
invoke_malloc_hook(p, sz);
|
||||
return p;
|
||||
}
|
||||
|
||||
// void *operator new(size_t, nothrow_t)
|
||||
TSAN_INTERCEPTOR(void*, _ZnwmRKSt9nothrow_t, uptr sz) {
|
||||
void *p = 0;
|
||||
{
|
||||
SCOPED_TSAN_INTERCEPTOR(_ZnwmRKSt9nothrow_t, sz);
|
||||
p = user_alloc(thr, pc, sz);
|
||||
}
|
||||
invoke_malloc_hook(p, sz);
|
||||
return p;
|
||||
}
|
||||
|
||||
// void *operator new[](size_t)
|
||||
TSAN_INTERCEPTOR(void*, _Znam, uptr sz) {
|
||||
void *p = 0;
|
||||
{
|
||||
SCOPED_TSAN_INTERCEPTOR(_Znam, sz);
|
||||
p = user_alloc(thr, pc, sz);
|
||||
}
|
||||
invoke_malloc_hook(p, sz);
|
||||
return p;
|
||||
}
|
||||
|
||||
// void *operator new[](size_t, nothrow_t)
|
||||
TSAN_INTERCEPTOR(void*, _ZnamRKSt9nothrow_t, uptr sz) {
|
||||
void *p = 0;
|
||||
{
|
||||
SCOPED_TSAN_INTERCEPTOR(_ZnamRKSt9nothrow_t, sz);
|
||||
p = user_alloc(thr, pc, sz);
|
||||
}
|
||||
invoke_malloc_hook(p, sz);
|
||||
return p;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Not implemented"
|
||||
#endif
|
||||
|
||||
// void operator delete(void*)
|
||||
TSAN_INTERCEPTOR(void, _ZdlPv, void *p) {
|
||||
if (p == 0)
|
||||
return;
|
||||
invoke_free_hook(p);
|
||||
SCOPED_TSAN_INTERCEPTOR(_ZdlPv, p);
|
||||
user_free(thr, pc, p);
|
||||
}
|
||||
|
||||
// void operator delete(void*, nothrow_t)
|
||||
TSAN_INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *p) {
|
||||
if (p == 0)
|
||||
return;
|
||||
invoke_free_hook(p);
|
||||
SCOPED_TSAN_INTERCEPTOR(_ZdlPvRKSt9nothrow_t, p);
|
||||
user_free(thr, pc, p);
|
||||
}
|
||||
|
||||
// void operator delete[](void*)
|
||||
TSAN_INTERCEPTOR(void, _ZdaPv, void *p) {
|
||||
if (p == 0)
|
||||
return;
|
||||
invoke_free_hook(p);
|
||||
SCOPED_TSAN_INTERCEPTOR(_ZdaPv, p);
|
||||
user_free(thr, pc, p);
|
||||
}
|
||||
|
||||
// void operator delete[](void*, nothrow_t)
|
||||
TSAN_INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *p) {
|
||||
if (p == 0)
|
||||
return;
|
||||
invoke_free_hook(p);
|
||||
SCOPED_TSAN_INTERCEPTOR(_ZdaPvRKSt9nothrow_t, p);
|
||||
user_free(thr, pc, p);
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
|
||||
SCOPED_TSAN_INTERCEPTOR(memalign, align, sz);
|
||||
return user_alloc(thr, pc, sz, align);
|
||||
|
@ -1447,7 +1299,7 @@ static void process_pending_signals(ThreadState *thr) {
|
|||
sigactions[sig].sa_handler(sig);
|
||||
if (errno != 0) {
|
||||
ScopedInRtl in_rtl;
|
||||
StackTrace stack;
|
||||
__tsan::StackTrace stack;
|
||||
uptr pc = signal->sigaction ?
|
||||
(uptr)sigactions[sig].sa_sigaction :
|
||||
(uptr)sigactions[sig].sa_handler;
|
||||
|
@ -1491,14 +1343,7 @@ void InitializeInterceptors() {
|
|||
TSAN_INTERCEPT(pvalloc);
|
||||
TSAN_INTERCEPT(posix_memalign);
|
||||
|
||||
TSAN_INTERCEPT(_Znwm);
|
||||
TSAN_INTERCEPT(_ZnwmRKSt9nothrow_t);
|
||||
TSAN_INTERCEPT(_Znam);
|
||||
TSAN_INTERCEPT(_ZnamRKSt9nothrow_t);
|
||||
TSAN_INTERCEPT(_ZdlPv);
|
||||
TSAN_INTERCEPT(_ZdlPvRKSt9nothrow_t);
|
||||
TSAN_INTERCEPT(_ZdaPv);
|
||||
TSAN_INTERCEPT(_ZdaPvRKSt9nothrow_t);
|
||||
ReplaceOperatorsNewAndDelete();
|
||||
|
||||
TSAN_INTERCEPT(strlen);
|
||||
TSAN_INTERCEPT(memset);
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
//===-- tsan_interceptors.h -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef TSAN_INTERCEPTORS_H
|
||||
#define TSAN_INTERCEPTORS_H
|
||||
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
#include "tsan_rtl.h"
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
class ScopedInterceptor {
|
||||
public:
|
||||
ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc);
|
||||
~ScopedInterceptor();
|
||||
private:
|
||||
ThreadState *const thr_;
|
||||
const int in_rtl_;
|
||||
};
|
||||
|
||||
#define SCOPED_INTERCEPTOR_RAW(func, ...) \
|
||||
ThreadState *thr = cur_thread(); \
|
||||
StatInc(thr, StatInterceptor); \
|
||||
StatInc(thr, StatInt_##func); \
|
||||
const uptr caller_pc = GET_CALLER_PC(); \
|
||||
ScopedInterceptor si(thr, #func, caller_pc); \
|
||||
/* Subtract one from pc as we need current instruction address */ \
|
||||
const uptr pc = __sanitizer::StackTrace::GetCurrentPc() - 1; \
|
||||
(void)pc; \
|
||||
/**/
|
||||
|
||||
#define SCOPED_TSAN_INTERCEPTOR(func, ...) \
|
||||
SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \
|
||||
if (thr->in_rtl > 1) \
|
||||
return REAL(func)(__VA_ARGS__); \
|
||||
/**/
|
||||
|
||||
#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
|
||||
#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // TSAN_INTERCEPTORS_H
|
|
@ -17,6 +17,16 @@
|
|||
#include "tsan_report.h"
|
||||
#include "tsan_flags.h"
|
||||
|
||||
// May be overriden by front-end.
|
||||
extern "C" void WEAK __tsan_malloc_hook(void *ptr, uptr size) {
|
||||
(void)ptr;
|
||||
(void)size;
|
||||
}
|
||||
|
||||
extern "C" void WEAK __tsan_free_hook(void *ptr) {
|
||||
(void)ptr;
|
||||
}
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
static char allocator_placeholder[sizeof(Allocator)] ALIGNED(64);
|
||||
|
@ -109,6 +119,22 @@ MBlock *user_mblock(ThreadState *thr, void *p) {
|
|||
return (MBlock*)allocator()->GetMetaData(p);
|
||||
}
|
||||
|
||||
void invoke_malloc_hook(void *ptr, uptr size) {
|
||||
Context *ctx = CTX();
|
||||
ThreadState *thr = cur_thread();
|
||||
if (ctx == 0 || !ctx->initialized || thr->in_rtl)
|
||||
return;
|
||||
__tsan_malloc_hook(ptr, size);
|
||||
}
|
||||
|
||||
void invoke_free_hook(void *ptr) {
|
||||
Context *ctx = CTX();
|
||||
ThreadState *thr = cur_thread();
|
||||
if (ctx == 0 || !ctx->initialized || thr->in_rtl)
|
||||
return;
|
||||
__tsan_free_hook(ptr);
|
||||
}
|
||||
|
||||
void *internal_alloc(MBlockType typ, uptr sz) {
|
||||
ThreadState *thr = cur_thread();
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
|
|
|
@ -33,6 +33,10 @@ void *user_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align);
|
|||
// returns the descriptor of the block.
|
||||
MBlock *user_mblock(ThreadState *thr, void *p);
|
||||
|
||||
// Invoking malloc/free hooks that may be installed by the user.
|
||||
void invoke_malloc_hook(void *ptr, uptr size);
|
||||
void invoke_free_hook(void *ptr);
|
||||
|
||||
enum MBlockType {
|
||||
MBlockScopedBuf,
|
||||
MBlockString,
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
//===-- tsan_new_delete.cc ------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
// Interceptors for operators new and delete.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "tsan_interceptors.h"
|
||||
#include "tsan_mman.h"
|
||||
#include "tsan_rtl.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <new>
|
||||
|
||||
namespace __tsan {
|
||||
// This function is a no-op. We need it to make sure that object file
|
||||
// with our replacements will actually be loaded from static TSan
|
||||
// run-time library at link-time.
|
||||
void ReplaceOperatorsNewAndDelete() { }
|
||||
}
|
||||
|
||||
using namespace __tsan; // NOLINT
|
||||
|
||||
#define OPERATOR_NEW_BODY(mangled_name) \
|
||||
void *p = 0; \
|
||||
{ \
|
||||
SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
|
||||
p = user_alloc(thr, pc, size); \
|
||||
} \
|
||||
invoke_malloc_hook(p, size); \
|
||||
return p;
|
||||
|
||||
void *operator new(size_t size) throw(std::bad_alloc) {
|
||||
OPERATOR_NEW_BODY(_Znwm);
|
||||
}
|
||||
void *operator new[](size_t size) throw(std::bad_alloc) {
|
||||
OPERATOR_NEW_BODY(_Znam);
|
||||
}
|
||||
void *operator new(size_t size, std::nothrow_t const&) throw() {
|
||||
OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t);
|
||||
}
|
||||
void *operator new[](size_t size, std::nothrow_t const&) throw() {
|
||||
OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t);
|
||||
}
|
||||
|
||||
#define OPERATOR_DELETE_BODY(mangled_name) \
|
||||
if (ptr == 0) return; \
|
||||
invoke_free_hook(ptr); \
|
||||
SCOPED_INTERCEPTOR_RAW(mangled_name, ptr); \
|
||||
user_free(thr, pc, ptr);
|
||||
|
||||
void operator delete(void *ptr) throw() {
|
||||
OPERATOR_DELETE_BODY(_ZdlPv);
|
||||
}
|
||||
void operator delete[](void *ptr) throw() {
|
||||
OPERATOR_DELETE_BODY(_ZdlPvRKSt9nothrow_t);
|
||||
}
|
||||
void operator delete(void *ptr, std::nothrow_t const&) throw() {
|
||||
OPERATOR_DELETE_BODY(_ZdaPv);
|
||||
}
|
||||
void operator delete[](void *ptr, std::nothrow_t const&) throw() {
|
||||
OPERATOR_DELETE_BODY(_ZdaPvRKSt9nothrow_t);
|
||||
}
|
|
@ -436,6 +436,7 @@ void ALWAYS_INLINE INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) {
|
|||
void InitializeShadowMemory();
|
||||
void InitializeInterceptors();
|
||||
void InitializeDynamicAnnotations();
|
||||
void ReplaceOperatorsNewAndDelete();
|
||||
|
||||
void ReportRace(ThreadState *thr);
|
||||
bool OutputReport(const ScopedReport &srep,
|
||||
|
|
Loading…
Reference in New Issue