tsan: do not call malloc/free in memory access handling routine.

This improves signal-/fork-safety of instrumented programs.

llvm-svn: 158988
This commit is contained in:
Dmitry Vyukov 2012-06-22 11:08:55 +00:00
parent b5f971f744
commit de1fd1c83b
7 changed files with 51 additions and 8 deletions

View File

@ -29,6 +29,7 @@ const int kTidBits = 13;
const unsigned kMaxTid = 1 << kTidBits;
const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
const int kClkBits = 43;
const int kShadowStackSize = 1024;
#ifdef TSAN_SHADOW_COUNT
# if TSAN_SHADOW_COUNT == 2 \

View File

@ -104,12 +104,20 @@ MBlock *user_mblock(ThreadState *thr, void *p) {
void *internal_alloc(MBlockType typ, uptr sz) {
ThreadState *thr = cur_thread();
CHECK_GT(thr->in_rtl, 0);
if (thr->nomalloc) {
thr->nomalloc = 0; // CHECK calls internal_malloc().
CHECK(0);
}
return InternalAlloc(sz);
}
void internal_free(void *p) {
ThreadState *thr = cur_thread();
CHECK_GT(thr->in_rtl, 0);
if (thr->nomalloc) {
thr->nomalloc = 0; // CHECK calls internal_malloc().
CHECK(0);
}
InternalFree(p);
}

View File

@ -219,12 +219,14 @@ int Finalize(ThreadState *thr) {
}
static void TraceSwitch(ThreadState *thr) {
thr->nomalloc++;
ScopedInRtl in_rtl;
Lock l(&thr->trace.mtx);
unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % kTraceParts;
TraceHeader *hdr = &thr->trace.headers[trace];
hdr->epoch0 = thr->fast_state.epoch();
hdr->stack0.ObtainCurrent(thr, 0);
thr->nomalloc--;
}
extern "C" void __tsan_trace_switch() {

View File

@ -204,7 +204,6 @@ class Shadow: public FastState {
const u64 kShadowFreed = 0xfffffffffffffff8ull;
const int kSigCount = 128;
const int kShadowStackSize = 1024;
struct my_siginfo_t {
int opaque[128];
@ -255,6 +254,9 @@ struct ThreadState {
int int_signal_send;
int pending_signal_count;
SignalDesc pending_signals[kSigCount];
// Set in regions of runtime that must be signal-safe and fork-safe.
// If set, malloc must not be called.
int nomalloc;
explicit ThreadState(Context *ctx, int tid, u64 epoch,
uptr stk_addr, uptr stk_size,

View File

@ -133,7 +133,16 @@ int SyncTab::PartIdx(uptr addr) {
StackTrace::StackTrace()
: n_()
, s_() {
, s_()
, c_() {
}
StackTrace::StackTrace(uptr *buf, uptr cnt)
: n_()
, s_(buf)
, c_(cnt) {
CHECK_NE(buf, 0);
CHECK_NE(cnt, 0);
}
StackTrace::~StackTrace() {
@ -141,21 +150,26 @@ StackTrace::~StackTrace() {
}
void StackTrace::Reset() {
if (s_) {
if (s_ && !c_) {
CHECK_NE(n_, 0);
internal_free(s_);
s_ = 0;
n_ = 0;
}
n_ = 0;
}
void StackTrace::Init(const uptr *pcs, uptr cnt) {
Reset();
if (cnt == 0)
return;
if (c_) {
CHECK_NE(s_, 0);
CHECK_LE(cnt, c_);
} else {
s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0]));
}
n_ = cnt;
s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0]));
REAL(memcpy)(s_, pcs, cnt * sizeof(s_[0]));
internal_memcpy(s_, pcs, cnt * sizeof(s_[0]));
}
void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
@ -163,7 +177,13 @@ void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
n_ = thr->shadow_stack_pos - &thr->shadow_stack[0];
if (n_ + !!toppc == 0)
return;
s_ = (uptr*)internal_alloc(MBlockStackTrace, (n_ + !!toppc) * sizeof(s_[0]));
if (c_) {
CHECK_NE(s_, 0);
CHECK_LE(n_ + !!toppc, c_);
} else {
s_ = (uptr*)internal_alloc(MBlockStackTrace,
(n_ + !!toppc) * sizeof(s_[0]));
}
for (uptr i = 0; i < n_; i++)
s_[i] = thr->shadow_stack[i];
if (toppc) {

View File

@ -25,6 +25,9 @@ class SlabCache;
class StackTrace {
public:
StackTrace();
// Initialized the object in "static mode",
// in this mode it never calls malloc/free but uses the provided buffer.
StackTrace(uptr *buf, uptr cnt);
~StackTrace();
void Reset();
@ -39,6 +42,7 @@ class StackTrace {
private:
uptr n_;
uptr *s_;
const uptr c_;
StackTrace(const StackTrace&);
void operator = (const StackTrace&);

View File

@ -41,7 +41,13 @@ typedef u64 Event;
struct TraceHeader {
StackTrace stack0; // Start stack for the trace.
u64 epoch0; // Start epoch for the trace.
u64 epoch0; // Start epoch for the trace.
uptr stack0buf[kShadowStackSize];
TraceHeader()
: stack0(stack0buf, kShadowStackSize)
, epoch0() {
}
};
struct Trace {