[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:
Alexey Samsonov 2012-09-24 13:19:47 +00:00
parent a555b3faf4
commit 313014694f
8 changed files with 181 additions and 178 deletions

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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);
}

View File

@ -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,