From f6cb35abb4ded28fb54a232e90e440e08ca8d727 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 13 Feb 2014 09:52:15 +0000 Subject: [PATCH] [sanitizer] findPath for deadlock detector llvm-svn: 201306 --- .../sanitizer_common/sanitizer_bitvector.h | 7 ++++++ .../lib/sanitizer_common/sanitizer_bvgraph.h | 22 +++++++++++++++++-- .../sanitizer_deadlock_detector.h | 2 ++ .../tests/sanitizer_bvgraph_test.cc | 19 +++++++++++++++- 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h b/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h index da9082f0ba26..5def7e1e6045 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_bitvector.h @@ -56,6 +56,8 @@ class BasicBitVector { return bits_ != old; } + void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; } + // Returns true if 'this' intersects with 'v'. bool intersectsWith(const BasicBitVector &v) const { return bits_ & v.bits_; } @@ -165,6 +167,11 @@ class TwoLevelBitVector { return res; } + void copyFrom(const TwoLevelBitVector &v) { + clear(); + setUnion(v); + } + // Returns true if 'this' intersects with 'v'. bool intersectsWith(const TwoLevelBitVector &v) const { for (uptr i0 = 0; i0 < kLevel1Size; i0++) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h b/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h index 5673a7a3075a..4ad43604bd5e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_bvgraph.h @@ -47,8 +47,7 @@ class BVGraph { // to any of the nodes in 'targets'. bool isReachable(uptr from, const BV &targets) { BV to_visit, visited; - to_visit.clear(); - to_visit.setUnion(v[from]); + to_visit.copyFrom(v[from]); visited.clear(); visited.setBit(from); while (!to_visit.empty()) { @@ -59,6 +58,25 @@ class BVGraph { return targets.intersectsWith(visited); } + // Finds a path from 'from' to one of the nodes in 'target', + // stores up to 'path_size' items of the path into 'path', + // returns the path length, or 0 if there is no path of size 'path_size'. + uptr findPath(uptr from, const BV &targets, uptr *path, uptr path_size) { + if (path_size == 0) + return 0; + path[0] = from; + if (targets.getBit(from)) + return 1; + BV t; + t.copyFrom(v[from]); + while (!t.empty()) { + uptr idx = t.getAndClearFirstOne(); + if (uptr res = findPath(idx, targets, path + 1, path_size - 1)) + return res + 1; + } + return 0; + } + private: void check(uptr idx) const { CHECK_LE(idx, size()); } BV v[kSize]; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h index d1da120d81aa..4f3f87d3bd45 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h @@ -59,6 +59,8 @@ class DeadlockDetectorTLS { // DeadlockDetector. // For deadlock detection to work we need one global DeadlockDetector object // and one DeadlockDetectorTLS object per evey thread. +// This class is not thread safe, all concurrent accesses should be guarded +// by an external lock. template class DeadlockDetector { public: diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc index d84ccdafd307..0e04ac87045a 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_bvgraph_test.cc @@ -61,7 +61,16 @@ TEST(SanitizerCommon, BVGraph) { from = my_rand() % g.size(); bool is_reachable = g.isReachable(from, target); if (is_reachable) { - // printf("reachable: %d %zd\n", it, from); + uptr path[BV::kSize]; + uptr len; + for (len = 1; len < BV::kSize; len++) { + if (g.findPath(from, target, path, len) == len) + break; + } + EXPECT_LT(len, BV::kSize); + EXPECT_TRUE(target.getBit(path[len - 1])); + // fprintf(stderr, "reachable: %zd; path %zd {%zd %zd %zd}\n", + // from, len, path[0], path[1], path[2]); num_reachable++; } } @@ -71,6 +80,7 @@ TEST(SanitizerCommon, BVGraph) { TEST(SanitizerCommon, BVGraph_isReachable) { typedef TwoLevelBitVector<> BV; + uptr path[5]; BVGraph g; g.clear(); BV target; @@ -103,6 +113,13 @@ TEST(SanitizerCommon, BVGraph_isReachable) { EXPECT_TRUE(g.isReachable(f1, target)); EXPECT_FALSE(g.isReachable(f2, target)); EXPECT_FALSE(g.isReachable(f3, target)); + EXPECT_EQ(g.findPath(f0, target, path, ARRAY_SIZE(path)), 3U); + EXPECT_EQ(path[0], f0); + EXPECT_EQ(path[1], f1); + EXPECT_EQ(path[2], t0); + EXPECT_EQ(g.findPath(f1, target, path, ARRAY_SIZE(path)), 2U); + EXPECT_EQ(path[0], f1); + EXPECT_EQ(path[1], t0); g.addEdge(f3, t1); EXPECT_TRUE(g.isReachable(f0, target));