forked from OSchip/llvm-project
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:
parent
b5f971f744
commit
de1fd1c83b
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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&);
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue