[llvm-commits] [compiler-rt] r156990 - in /compiler-rt/trunk/lib/tsan: output_tests/free_race.c output_tests/free_race2.c rtl/tsan_clock.cc rtl/tsan_clock.h rtl/tsan_defs.h rtl/tsan_report.cc rtl/tsan_report.h rtl/tsan_rtl.cc rtl/tsan_rtl.h rtl/tsan_rtl_report.cc
Dmitry Vyukov
dvyukov at google.com
Thu May 17 07:17:52 PDT 2012
Author: dvyukov
Date: Thu May 17 09:17:51 2012
New Revision: 156990
URL: http://llvm.org/viewvc/llvm-project?rev=156990&view=rev
Log:
tsan: detect accesses to freed memory
http://codereview.appspot.com/6214052
Added:
compiler-rt/trunk/lib/tsan/output_tests/free_race2.c
Modified:
compiler-rt/trunk/lib/tsan/output_tests/free_race.c
compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc
compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h
compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h
compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc
compiler-rt/trunk/lib/tsan/rtl/tsan_report.h
compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
Modified: compiler-rt/trunk/lib/tsan/output_tests/free_race.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/free_race.c?rev=156990&r1=156989&r2=156990&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/free_race.c (original)
+++ compiler-rt/trunk/lib/tsan/output_tests/free_race.c Thu May 17 09:17:51 2012
@@ -33,4 +33,11 @@
return 0;
}
-// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
+// CHECK: Write of size 4 at {{.*}} by main thread:
+// CHECK: #0 Thread2
+// CHECK: #1 main
+// CHECK: Previous write of size 8 at {{.*}} by thread 1:
+// CHECK: #0 free
+// CHECK: #1 Thread1
+
Added: compiler-rt/trunk/lib/tsan/output_tests/free_race2.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/free_race2.c?rev=156990&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/free_race2.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/free_race2.c Thu May 17 09:17:51 2012
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+
+void __attribute__((noinline)) foo(int *mem) {
+ free(mem);
+}
+
+void __attribute__((noinline)) bar(int *mem) {
+ mem[0] = 42;
+}
+
+int main() {
+ int *mem = (int*)malloc(100);
+ foo(mem);
+ bar(mem);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
+// CHECK: Write of size 4 at {{.*}} by main thread:
+// CHECK: #0 bar
+// CHECK: #1 main
+// CHECK: Previous write of size 8 at {{.*}} by main thread:
+// CHECK: #0 free
+// CHECK: #1 foo
+// CHECK: #2 main
+
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc?rev=156990&r1=156989&r2=156990&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc Thu May 17 09:17:51 2012
@@ -58,7 +58,7 @@
ThreadClock::ThreadClock() {
nclk_ = 0;
- for (uptr i = 0; i < (uptr)kMaxTid; i++)
+ for (uptr i = 0; i < (uptr)kMaxTidInClock; i++)
clk_[i] = 0;
}
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h?rev=156990&r1=156989&r2=156990&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h Thu May 17 09:17:51 2012
@@ -42,7 +42,7 @@
ThreadClock();
u64 get(unsigned tid) const {
- DCHECK(tid < kMaxTid);
+ DCHECK(tid < kMaxTidInClock);
return clk_[tid];
}
@@ -71,7 +71,7 @@
private:
uptr nclk_;
- u64 clk_[kMaxTid];
+ u64 clk_[kMaxTidInClock];
};
} // namespace __tsan
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h?rev=156990&r1=156989&r2=156990&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h Thu May 17 09:17:51 2012
@@ -29,8 +29,9 @@
typedef unsigned long uptr; // NOLINT
const uptr kPageSize = 4096;
-const int kTidBits = 16;
+const int kTidBits = 15;
const unsigned kMaxTid = 1 << kTidBits;
+const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
const int kClkBits = 40;
#ifdef TSAN_SHADOW_COUNT
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc?rev=156990&r1=156989&r2=156990&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc Thu May 17 09:17:51 2012
@@ -32,6 +32,8 @@
if (typ == ReportTypeRace)
Printf("data race");
+ else if (typ == ReportTypeUseAfterFree)
+ Printf("heap-use-after-free");
else if (typ == ReportTypeThreadLeak)
Printf("thread leak");
else if (typ == ReportTypeMutexDestroyLocked)
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_report.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_report.h?rev=156990&r1=156989&r2=156990&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_report.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_report.h Thu May 17 09:17:51 2012
@@ -20,6 +20,7 @@
enum ReportType {
ReportTypeRace,
+ ReportTypeUseAfterFree,
ReportTypeThreadLeak,
ReportTypeMutexDestroyLocked,
ReportTypeSignalUnsafe,
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc?rev=156990&r1=156989&r2=156990&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc Thu May 17 09:17:51 2012
@@ -373,7 +373,11 @@
void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
MemoryAccessRange(thr, pc, addr, size, true);
- MemoryRangeSet(thr, pc, addr, size, kShadowFreed);
+ Shadow s(thr->fast_state);
+ s.MarkAsFreed();
+ s.SetWrite(true);
+ s.SetAddr0AndSizeLog(0, 3);
+ MemoryRangeSet(thr, pc, addr, size, s.raw());
}
void FuncEntry(ThreadState *thr, uptr pc) {
@@ -389,16 +393,6 @@
DCHECK(thr->shadow_stack_pos < &thr->shadow_stack[kShadowStackSize]);
thr->shadow_stack_pos[0] = pc;
thr->shadow_stack_pos++;
-
-#if 1
- // While we are testing on single-threaded benchmarks,
- // emulate some synchronization activity.
- // FIXME: remove me later.
- if (((++thr->func_call_count) % 1000) == 0) {
- thr->clock.set(thr->fast_state.tid(), thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- }
-#endif
}
void FuncExit(ThreadState *thr) {
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=156990&r1=156989&r2=156990&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Thu May 17 09:17:51 2012
@@ -45,17 +45,18 @@
}
// FastState (from most significant bit):
+// unused : 1
// tid : kTidBits
// epoch : kClkBits
-// unused :
+// unused : -
// ignore_bit : 1
class FastState {
public:
FastState(u64 tid, u64 epoch) {
- x_ = tid << (64 - kTidBits);
- x_ |= epoch << (64 - kTidBits - kClkBits);
- CHECK(tid == this->tid());
- CHECK(epoch == this->epoch());
+ x_ = tid << kTidShift;
+ x_ |= epoch << kClkShift;
+ DCHECK(tid == this->tid());
+ DCHECK(epoch == this->epoch());
}
explicit FastState(u64 x)
@@ -63,28 +64,37 @@
}
u64 tid() const {
- u64 res = x_ >> (64 - kTidBits);
+ u64 res = x_ >> kTidShift;
return res;
}
+
u64 epoch() const {
- u64 res = (x_ << kTidBits) >> (64 - kClkBits);
+ u64 res = (x_ << (kTidBits + 1)) >> (64 - kClkBits);
return res;
- };
+ }
+
void IncrementEpoch() {
- // u64 old_epoch = epoch();
- x_ += 1 << (64 - kTidBits - kClkBits);
- // CHECK(old_epoch + 1 == epoch());
- }
- void SetIgnoreBit() { x_ |= 1; }
- void ClearIgnoreBit() { x_ &= ~(u64)1; }
- bool GetIgnoreBit() { return x_ & 1; }
+ u64 old_epoch = epoch();
+ x_ += 1 << kClkShift;
+ DCHECK(old_epoch + 1 == epoch());
+ (void)old_epoch;
+ }
+
+ void SetIgnoreBit() { x_ |= kIgnoreBit; }
+ void ClearIgnoreBit() { x_ &= ~kIgnoreBit; }
+ bool GetIgnoreBit() { return x_ & kIgnoreBit; }
private:
friend class Shadow;
+ static const int kTidShift = 64 - kTidBits - 1;
+ static const int kClkShift = kTidShift - kClkBits;
+ static const u64 kIgnoreBit = 1ull;
+ static const u64 kFreedBit = 1ull << 63;
u64 x_;
};
// Shadow (from most significant bit):
+// freed : 1
// tid : kTidBits
// epoch : kClkBits
// is_write : 1
@@ -116,7 +126,7 @@
u64 raw() const { return x_; }
static inline bool TidsAreEqual(Shadow s1, Shadow s2) {
- u64 shifted_xor = (s1.x_ ^ s2.x_) >> (64 - kTidBits);
+ u64 shifted_xor = (s1.x_ ^ s2.x_) >> kTidShift;
DCHECK_EQ(shifted_xor == 0, s1.tid() == s2.tid());
return shifted_xor == 0;
}
@@ -170,6 +180,25 @@
u64 size() const { return 1ull << size_log(); }
bool is_write() const { return x_ & 32; }
+ // The idea behind the freed bit is as follows.
+ // When the memory is freed (or otherwise unaccessible) we write to the shadow
+ // values with tid/epoch related to the free and the freed bit set.
+ // During memory accesses processing the freed bit is considered
+ // as msb of tid. So any access races with shadow with freed bit set
+ // (it is as if write from a thread with which we never synchronized before).
+ // This allows us to detect accesses to freed memory w/o additional
+ // overheads in memory access processing and at the same time restore
+ // tid/epoch of free.
+ void MarkAsFreed() {
+ x_ |= kFreedBit;
+ }
+
+ bool GetFreedAndReset() {
+ bool res = x_ & kFreedBit;
+ x_ &= ~kFreedBit;
+ return res;
+ }
+
private:
u64 size_log() const { return (x_ >> 3) & 3; }
};
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc?rev=156990&r1=156989&r2=156990&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc Thu May 17 09:17:51 2012
@@ -286,6 +286,14 @@
void ReportRace(ThreadState *thr) {
ScopedInRtl in_rtl;
+
+ bool freed = false;
+ {
+ Shadow s(thr->racy_state[1]);
+ freed = s.GetFreedAndReset();
+ thr->racy_state[1] = s.raw();
+ }
+
uptr addr = ShadowToMem((uptr)thr->racy_shadow_addr);
uptr addr_min = 0;
uptr addr_max = 0;
@@ -303,11 +311,10 @@
Context *ctx = CTX();
Lock l0(&ctx->thread_mtx);
- ScopedReport rep(ReportTypeRace);
- const uptr nmop = thr->racy_state[1] == kShadowFreed ? 1 : 2;
-
- StackTrace traces[2];
- for (uptr i = 0; i < nmop; i++) {
+ ScopedReport rep(freed ? ReportTypeUseAfterFree : ReportTypeRace);
+ const uptr kMop = 2;
+ StackTrace traces[kMop];
+ for (uptr i = 0; i < kMop; i++) {
Shadow s(thr->racy_state[i]);
RestoreStack(s.tid(), s.epoch(), &traces[i]);
}
@@ -315,7 +322,7 @@
if (HandleRacyStacks(thr, traces, addr_min, addr_max))
return;
- for (uptr i = 0; i < nmop; i++) {
+ for (uptr i = 0; i < kMop; i++) {
Shadow s(thr->racy_state[i]);
rep.AddMemoryAccess(addr, s, &traces[i]);
}
@@ -323,7 +330,7 @@
// Ensure that we have at least something for the current thread.
CHECK_EQ(traces[0].IsEmpty(), false);
- for (uptr i = 0; i < nmop; i++) {
+ for (uptr i = 0; i < kMop; i++) {
FastState s(thr->racy_state[i]);
ThreadContext *tctx = ctx->threads[s.tid()];
if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1)
More information about the llvm-commits
mailing list