diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.h @@ -41,6 +41,7 @@ void StackDepotLockAll(); void StackDepotUnlockAll(); +void StackDepotPrintAll(); // Instantiating this class creates a snapshot of StackDepot which can be // efficiently queried with StackDepotGet(). You can use it concurrently with diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp @@ -115,6 +115,12 @@ theDepot.UnlockAll(); } +void StackDepotPrintAll() { +#if !SANITIZER_GO + theDepot.PrintAll(); +#endif +} + bool StackDepotReverseMap::IdDescPair::IdComparator( const StackDepotReverseMap::IdDescPair &a, const StackDepotReverseMap::IdDescPair &b) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stackdepotbase.h @@ -13,9 +13,11 @@ #ifndef SANITIZER_STACKDEPOTBASE_H #define SANITIZER_STACKDEPOTBASE_H +#include + +#include "sanitizer_atomic.h" #include "sanitizer_internal_defs.h" #include "sanitizer_mutex.h" -#include "sanitizer_atomic.h" #include "sanitizer_persistent_allocator.h" namespace __sanitizer { @@ -34,6 +36,7 @@ void LockAll(); void UnlockAll(); + void PrintAll(); private: static Node *find(Node *s, args_type args, u32 hash); @@ -172,6 +175,21 @@ } } +template +void StackDepotBase::PrintAll() { + for (int i = 0; i < kTabSize; ++i) { + atomic_uintptr_t *p = &tab[i]; + lock(p); + uptr v = atomic_load(p, memory_order_relaxed); + Node *s = (Node *)(v & ~1UL); + for (; s; s = s->link) { + Printf("Stack for id %u:\n", s->id); + s->load().Print(); + } + unlock(p, s); + } +} + } // namespace __sanitizer #endif // SANITIZER_STACKDEPOTBASE_H diff --git a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt --- a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt @@ -53,6 +53,7 @@ set(SANITIZER_TEST_CFLAGS_COMMON ${COMPILER_RT_UNITTEST_CFLAGS} ${COMPILER_RT_GTEST_CFLAGS} + ${COMPILER_RT_GMOCK_CFLAGS} -I${COMPILER_RT_SOURCE_DIR}/include -I${COMPILER_RT_SOURCE_DIR}/lib -I${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common @@ -151,7 +152,7 @@ generate_compiler_rt_tests(SANITIZER_TEST_OBJECTS SanitizerUnitTests "Sanitizer-${arch}-Test" ${arch} RUNTIME "${SANITIZER_COMMON_LIB}" - SOURCES ${SANITIZER_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE} + SOURCES ${SANITIZER_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE} ${COMPILER_RT_GMOCK_SOURCE} COMPILE_DEPS ${SANITIZER_TEST_HEADERS} DEPS gtest CFLAGS ${SANITIZER_TEST_CFLAGS_COMMON} ${extra_flags} @@ -207,6 +208,7 @@ add_executable(SanitizerTest ${SANITIZER_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE} + ${COMPILER_RT_GMOCK_SOURCE} $ $ $) diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cpp --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stackdepot_test.cpp @@ -10,9 +10,14 @@ // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_stackdepot.h" + +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_libc.h" -#include "gtest/gtest.h" +#include "sanitizer_common/sanitizer_posix.h" namespace __sanitizer { @@ -64,6 +69,32 @@ EXPECT_NE(i1, i2); } +TEST(SanitizerCommon, StackDepotPrint) { + uptr array1[] = {1, 2, 3, 4, 7}; + StackTrace s1(array1, ARRAY_SIZE(array1)); + u32 i1 = StackDepotPut(s1); + uptr array2[] = {1, 2, 3, 4, 8, 9}; + StackTrace s2(array2, ARRAY_SIZE(array2)); + u32 i2 = StackDepotPut(s2); + EXPECT_NE(i1, i2); + char tmpfile[128]; + const char *tmpdir = "/tmp"; + internal_snprintf(tmpfile, sizeof(tmpfile), "%s/%sXXXXXX", tmpdir, + "sanitizer_common.stackdepotprint.tmp."); + fd_t fd = mkstemp(tmpfile); + __sanitizer_set_report_fd(reinterpret_cast(fd)); + StackDepotPrintAll(); + std::ifstream t(tmpfile); + std::stringstream buffer; + buffer << t.rdbuf(); + EXPECT_THAT( + buffer.str(), + testing::MatchesRegex( + "Stack for id .*#0 0x0.*#1 0x1.*#2 0x2.*#3 0x3.*#4 0x6.*Stack for id " + ".*#0 0x0.*#1 0x1.*#2 0x2.*#3 0x3.*#4 0x7.*#5 0x8.*")); + internal_unlink(tmpfile); +} + TEST(SanitizerCommon, StackDepotReverseMap) { uptr array1[] = {1, 2, 3, 4, 5}; uptr array2[] = {7, 1, 3, 0};