From 8a0a3101bc6a7d56ac04b278f28bdf3f95b00a3c Mon Sep 17 00:00:00 2001 From: csilvers Date: Wed, 13 Feb 2008 00:55:09 +0000 Subject: Tue Feb 12 12:28:32 2008 Google Inc. * google-perftools: version 0.95 release * Better -- not perfect -- support for linux-ppc (csilvers) * Fix race condition in libunwind stacktrace (aruns) * Speed up x86 spinlock locking (m3b) * Improve heap-checker performance (maxim) * Heap checker traverses more ptrs inside heap-alloced objects (maxim) * Remove deprecated ProfilerThreadState function (cgd) * Update libunwind documentation for statically linked binaries (aruns) git-svn-id: http://gperftools.googlecode.com/svn/trunk@44 6b5cf1ce-ec42-a296-1ba9-69fdba395a50 --- src/tests/addressmap_unittest.cc | 108 +++++++++---- src/tests/heap-checker_unittest.cc | 316 ++++++++++++++++++++++++++----------- src/tests/profiler_unittest.cc | 2 +- src/tests/stacktrace_unittest.cc | 13 +- src/tests/tcmalloc_unittest.cc | 2 +- 5 files changed, 307 insertions(+), 134 deletions(-) (limited to 'src/tests') diff --git a/src/tests/addressmap_unittest.cc b/src/tests/addressmap_unittest.cc index 50d9b94..6b65cc3 100644 --- a/src/tests/addressmap_unittest.cc +++ b/src/tests/addressmap_unittest.cc @@ -30,6 +30,7 @@ // --- // Author: Sanjay Ghemawat +#include // for rand() #include #include #include @@ -47,62 +48,102 @@ using std::vector; using std::set; using std::random_shuffle; -static void SetCheckCallback(const void* ptr, int val, +struct UniformRandomNumberGenerator { + size_t Uniform(size_t max_size) { + if (max_size == 0) + return 0; + return rand() % max_size; // not a great random-number fn, but portable + } +}; +static UniformRandomNumberGenerator rnd; + + +// pair of associated value and object size +typedef pair ValueT; + +struct PtrAndSize { + char* ptr; + size_t size; + PtrAndSize(char* p, size_t s) : ptr(p), size(s) {} +}; + +size_t SizeFunc(const ValueT& v) { return v.second; } + +static void SetCheckCallback(const void* ptr, ValueT* val, set >* check_set) { - check_set->insert(make_pair(ptr, val)); + check_set->insert(make_pair(ptr, val->first)); } int main(int argc, char** argv) { // Get a bunch of pointers const int N = FLAGS_N; - static const int kObjectLength = 19; - vector ptrs; + static const int kMaxRealSize = 49; + // 100Mb to stress not finding previous object (AddressMap's cluster is 1Mb): + static const size_t kMaxSize = 100*1000*1000; + vector ptrs_and_sizes; for (int i = 0; i < N; ++i) { - ptrs.push_back(new char[kObjectLength]); + size_t s = rnd.Uniform(kMaxRealSize); + ptrs_and_sizes.push_back(PtrAndSize(new char[s], s)); } for (int x = 0; x < FLAGS_iters; ++x) { // Permute pointers to get rid of allocation order issues - random_shuffle(ptrs.begin(), ptrs.end()); + random_shuffle(ptrs_and_sizes.begin(), ptrs_and_sizes.end()); - AddressMap map(malloc, free); - int result; + AddressMap map(malloc, free); + const ValueT* result; + const void* res_p; // Insert a bunch of entries for (int i = 0; i < N; ++i) { - void* p = ptrs[i]; - CHECK(!map.Find(p, &result)); - map.Insert(p, i); - CHECK(map.Find(p, &result)); - CHECK_EQ(result, i); - map.Insert(p, i + N); - CHECK(map.Find(p, &result)); - CHECK_EQ(result, i + N); + char* p = ptrs_and_sizes[i].ptr; + CHECK(!map.Find(p)); + int offs = rnd.Uniform(ptrs_and_sizes[i].size); + CHECK(!map.FindInside(&SizeFunc, kMaxSize, p + offs, &res_p)); + map.Insert(p, make_pair(i, ptrs_and_sizes[i].size)); + CHECK(result = map.Find(p)); + CHECK_EQ(result->first, i); + CHECK(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p)); + CHECK_EQ(res_p, p); + CHECK_EQ(result->first, i); + map.Insert(p, make_pair(i + N, ptrs_and_sizes[i].size)); + CHECK(result = map.Find(p)); + CHECK_EQ(result->first, i + N); } // Delete the even entries for (int i = 0; i < N; i += 2) { - void* p = ptrs[i]; - CHECK(map.FindAndRemove(p, &result)); - CHECK_EQ(result, i + N); + void* p = ptrs_and_sizes[i].ptr; + ValueT removed; + CHECK(map.FindAndRemove(p, &removed)); + CHECK_EQ(removed.first, i + N); } // Lookup the odd entries and adjust them for (int i = 1; i < N; i += 2) { - void* p = ptrs[i]; - CHECK(map.Find(p, &result)); - CHECK_EQ(result, i + N); - map.Insert(p, i + 2*N); - CHECK(map.Find(p, &result)); - CHECK_EQ(result, i + 2*N); + char* p = ptrs_and_sizes[i].ptr; + CHECK(result = map.Find(p)); + CHECK_EQ(result->first, i + N); + int offs = rnd.Uniform(ptrs_and_sizes[i].size); + CHECK(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p)); + CHECK_EQ(res_p, p); + CHECK_EQ(result->first, i + N); + map.Insert(p, make_pair(i + 2*N, ptrs_and_sizes[i].size)); + CHECK(result = map.Find(p)); + CHECK_EQ(result->first, i + 2*N); } // Insert even entries back for (int i = 0; i < N; i += 2) { - void* p = ptrs[i]; - map.Insert(p, i + 2*N); - CHECK(map.Find(p, &result)); - CHECK_EQ(result, i + 2*N); + char* p = ptrs_and_sizes[i].ptr; + int offs = rnd.Uniform(ptrs_and_sizes[i].size); + CHECK(!map.FindInside(&SizeFunc, kMaxSize, p + offs, &res_p)); + map.Insert(p, make_pair(i + 2*N, ptrs_and_sizes[i].size)); + CHECK(result = map.Find(p)); + CHECK_EQ(result->first, i + 2*N); + CHECK(result = map.FindInside(&SizeFunc, kMaxRealSize, p + offs, &res_p)); + CHECK_EQ(res_p, p); + CHECK_EQ(result->first, i + 2*N); } // Check all entries @@ -110,17 +151,16 @@ int main(int argc, char** argv) { map.Iterate(SetCheckCallback, &check_set); CHECK_EQ(check_set.size(), N); for (int i = 0; i < N; ++i) { - void* p = ptrs[i]; + void* p = ptrs_and_sizes[i].ptr; check_set.erase(make_pair(p, i + 2*N)); - CHECK(map.Find(p, &result)); - CHECK_EQ(result, i + 2*N); + CHECK(result = map.Find(p)); + CHECK_EQ(result->first, i + 2*N); } CHECK_EQ(check_set.size(), 0); - } for (int i = 0; i < N; ++i) { - delete[] ptrs[i]; + delete[] ptrs_and_sizes[i].ptr; } printf("PASS\n"); diff --git a/src/tests/heap-checker_unittest.cc b/src/tests/heap-checker_unittest.cc index 5b64b8b..ac38fb0 100644 --- a/src/tests/heap-checker_unittest.cc +++ b/src/tests/heap-checker_unittest.cc @@ -95,6 +95,7 @@ #include // for hex #include #include +#include #include #include #include @@ -115,6 +116,7 @@ using namespace std; +// ========================================================================= // // TODO(maxim): write a shell script to test that these indeed crash us // (i.e. we do detect leaks) @@ -156,6 +158,9 @@ DEFINE_bool(no_threads, // This is used so we can make can_create_leaks_reliably true // for any pthread implementation and test with that. +DECLARE_int64(heap_check_max_pointer_offset); // heap-checker.cc +DECLARE_string(heap_check); // in heap-checker.cc + #define WARN_IF(cond, msg) LOG_IF(WARNING, cond, msg) // This is an evil macro! Be very careful using it... @@ -164,6 +169,8 @@ DEFINE_bool(no_threads, // This is, likewise, evil #define LOGF VLOG(INFO) +static void RunHeapBusyThreads(); // below + class Closure { public: @@ -233,7 +240,7 @@ static bool can_create_leaks_reliably = false; // We use a simple allocation wrapper // to make sure we wipe out the newly allocated objects // in case they still happened to contain some pointer data -// accidently left by the memory allocator. +// accidentally left by the memory allocator. struct Initialized { }; static Initialized initialized; void* operator new(size_t size, const Initialized&) { @@ -833,6 +840,8 @@ static void TestLibCAllocate() { // Continuous random heap memory activity to try to disrupt heap checking. static void* HeapBusyThreadBody(void* a) { + const int thread_num = reinterpret_cast(a); + VLOG(0) << "A new HeapBusyThread " << thread_num; TestLibCAllocate(); int user = 0; @@ -878,7 +887,7 @@ static void* HeapBusyThreadBody(void* a) { << reinterpret_cast( reinterpret_cast(ptr) ^ kHideMask) << "^" << reinterpret_cast(kHideMask); - if (FLAGS_test_register_leak) { + if (FLAGS_test_register_leak && thread_num % 5 == 0) { // Hide the register "ptr" value with an xor mask. // If one provides --test_register_leak flag, the test should // (with very high probability) crash on some leak check @@ -913,7 +922,8 @@ static void* HeapBusyThreadBody(void* a) { } static void RunHeapBusyThreads() { - if (FLAGS_no_threads) return; + KeyInit(); + if (!FLAGS_interfering_threads || FLAGS_no_threads) return; const int n = 17; // make many threads @@ -923,7 +933,8 @@ static void RunHeapBusyThreads() { // make them and let them run for (int i = 0; i < n; ++i) { VLOG(0) << "Creating extra thread " << i + 1; - CHECK(pthread_create(&tid, &attr, HeapBusyThreadBody, NULL) == 0); + CHECK(pthread_create(&tid, &attr, HeapBusyThreadBody, + reinterpret_cast(i)) == 0); } Pause(); @@ -1038,10 +1049,62 @@ static void TestHeapLeakCheckerNamedDisabling() { } } -// The code from here to main() -// is to test that objects that are reachable from global -// variables are not reported as leaks, -// with the few exceptions like multiple-inherited objects. +// ========================================================================= // + +// This code section is to test that objects that are reachable from global +// variables are not reported as leaks +// as well as that (Un)IgnoreObject work for such objects fine. + +// An object making functions: +// returns a "weird" pointer to a new object for which +// it's worth checking that the object is reachable via that pointer. +typedef void* (*ObjMakerFunc)(); +static list obj_makers; // list of registered object makers + +// Helper macro to register an object making function +// 'name' is an identifier of this object maker, +// 'body' is its function body that must declare +// pointer 'p' to the nex object to return. +// Usage example: +// REGISTER_OBJ_MAKER(trivial, int* p = new(initialized) int;) +#define REGISTER_OBJ_MAKER(name, body) \ + void* ObjMaker_##name##_() { \ + VLOG(1) << "Obj making " << #name; \ + body; \ + return p; \ + } \ + static ObjMakerRegistrar maker_reg_##name##__(&ObjMaker_##name##_); +// helper class for REGISTER_OBJ_MAKER +struct ObjMakerRegistrar { + ObjMakerRegistrar(ObjMakerFunc obj_maker) { obj_makers.push_back(obj_maker); } +}; + +// List of the objects/pointers made with all the obj_makers +// to test reachability via global data pointers during leak checks. +static list* live_objects = new list; + // pointer so that it does not get destructed on exit + +// Exerciser for one ObjMakerFunc. +static void TestPointerReach(ObjMakerFunc obj_maker) { + HeapLeakChecker::IgnoreObject(obj_maker()); // test IgnoreObject + + void* obj = obj_maker(); + HeapLeakChecker::IgnoreObject(obj); + HeapLeakChecker::UnIgnoreObject(obj); // test UnIgnoreObject + HeapLeakChecker::IgnoreObject(obj); // not to need deletion for obj + + live_objects->push_back(obj_maker()); // test reachability at leak check +} + +// Test all ObjMakerFunc registred via REGISTER_OBJ_MAKER. +static void TestObjMakers() { + for (list::const_iterator i = obj_makers.begin(); + i != obj_makers.end(); ++i) { + TestPointerReach(*i); + TestPointerReach(*i); // a couple more times would not hurt + TestPointerReach(*i); + } +} // A dummy class to mimic allocation behavior of string-s. template @@ -1083,22 +1146,45 @@ struct Array { T* ptr; }; -static Array* live_leak = NULL; -static Array* live_leak2 = new(initialized) Array(); -static int* live_leak3 = new(initialized) int[10]; -static const char* live_leak4 = new(initialized) char[5]; -static int data[] = { 1, 2, 3, 4, 5, 6, 7, 21, 22, 23, 24, 25, 26, 27 }; -static set live_leak5(data, data+7); -static const set live_leak6(data, data+14); -static const Array* live_leak_arr1 = new(initialized) Array[5]; +// to test pointers to objects, built-in arrays, string, etc: +REGISTER_OBJ_MAKER(plain, int* p = new(initialized) int;) +REGISTER_OBJ_MAKER(int_array_1, int* p = new(initialized) int[1];) +REGISTER_OBJ_MAKER(int_array, int* p = new(initialized) int[10];) +REGISTER_OBJ_MAKER(string, Array* p = new(initialized) Array();) +REGISTER_OBJ_MAKER(string_array, + Array* p = new(initialized) Array[5];) +REGISTER_OBJ_MAKER(char_array, char* p = new(initialized) char[5];) +REGISTER_OBJ_MAKER(appended_string, + Array* p = new Array(); + p->append(Array()); +) +REGISTER_OBJ_MAKER(plain_ptr, int** p = new(initialized) int*;) +REGISTER_OBJ_MAKER(linking_ptr, + int** p = new(initialized) int*; + *p = new(initialized) int; +) + +// small objects: +REGISTER_OBJ_MAKER(0_sized, void* p = malloc(0);) // 0-sized object (important) +REGISTER_OBJ_MAKER(1_sized, void* p = malloc(1);) +REGISTER_OBJ_MAKER(2_sized, void* p = malloc(2);) +REGISTER_OBJ_MAKER(3_sized, void* p = malloc(3);) +REGISTER_OBJ_MAKER(4_sized, void* p = malloc(4);) + +static int set_data[] = { 1, 2, 3, 4, 5, 6, 7, 21, 22, 23, 24, 25, 26, 27 }; +static set live_leak_set(set_data, set_data+7); +static const set live_leak_const_set(set_data, set_data+14); + +REGISTER_OBJ_MAKER(set, + set* p = new(initialized) set(set_data, set_data + 13); +) class ClassA { public: ClassA(int a) : ptr(NULL) { } mutable char* ptr; }; - -static const ClassA live_leak7(1); +static const ClassA live_leak_mutable(1); template class TClass { @@ -1107,13 +1193,12 @@ class TClass { mutable C val; mutable C* ptr; }; - -static const TClass > live_leak8(1); +static const TClass > live_leak_templ_mutable(1); class ClassB { public: ClassB() { } - int b[10]; + char b[7]; virtual void f() { } virtual ~ClassB() { } }; @@ -1121,102 +1206,140 @@ class ClassB { class ClassB2 { public: ClassB2() { } - int b2[10]; + char b2[11]; virtual void f2() { } virtual ~ClassB2() { } }; class ClassD1 : public ClassB { - int d1[10]; + char d1[15]; virtual void f() { } }; class ClassD2 : public ClassB2 { - int d2[10]; + char d2[19]; virtual void f2() { } }; class ClassD : public ClassD1, public ClassD2 { - int d[10]; + char d[3]; virtual void f() { } virtual void f2() { } }; -static ClassB* live_leak_b; -static ClassD1* live_leak_d1; -static ClassD2* live_leak_d2; -static ClassD* live_leak_d; +// to test pointers to objects of base subclasses: -static ClassB* live_leak_b_d1; -static ClassB2* live_leak_b2_d2; -static ClassB* live_leak_b_d; -static ClassB2* live_leak_b2_d; +REGISTER_OBJ_MAKER(B, ClassB* p = new(initialized) ClassB;) +REGISTER_OBJ_MAKER(D1, ClassD1* p = new(initialized) ClassD1;) +REGISTER_OBJ_MAKER(D2, ClassD2* p = new(initialized) ClassD2;) +REGISTER_OBJ_MAKER(D, ClassD* p = new(initialized) ClassD;) -static ClassD1* live_leak_d1_d; -static ClassD2* live_leak_d2_d; +REGISTER_OBJ_MAKER(D1_as_B, ClassB* p = new(initialized) ClassD1;) +REGISTER_OBJ_MAKER(D2_as_B2, ClassB2* p = new(initialized) ClassD2;) +REGISTER_OBJ_MAKER(D_as_B, ClassB* p = new(initialized) ClassD;) +REGISTER_OBJ_MAKER(D_as_D1, ClassD1* p = new(initialized) ClassD;) +// inside-object pointers: +REGISTER_OBJ_MAKER(D_as_B2, ClassB2* p = new(initialized) ClassD;) +REGISTER_OBJ_MAKER(D_as_D2, ClassD2* p = new(initialized) ClassD;) -// A dummy string class mimics certain third party string -// implementations, which store a refcount in the first -// few bytes and keeps a pointer pointing behind the refcount. -template -class RefcountStr { +class InterfaceA { public: - RefcountStr() { - ptr = new char[sizeof(R) * 10]; - ptr = ptr + sizeof(R); - } - char* ptr; + virtual void A() = 0; + virtual ~InterfaceA() { } + protected: + InterfaceA() { } }; -// E.g., mimics UnicodeString defined in third_party/icu. -static const RefcountStr live_leak_refcountstr_4; - -// have leaks but ignore the leaked objects -static void IgnoredLeaks() { - int* p = new(initialized) int[1]; - HeapLeakChecker::IgnoreObject(p); - int** leak = new(initialized) int*; - HeapLeakChecker::IgnoreObject(leak); - *leak = new(initialized) int; - HeapLeakChecker::UnIgnoreObject(p); - delete [] p; -} + +class InterfaceB { + public: + virtual void B() = 0; + virtual ~InterfaceB() { } + protected: + InterfaceB() { } +}; + +class InterfaceC : public InterfaceA { + public: + virtual void C() = 0; + virtual ~InterfaceC() { } + protected: + InterfaceC() { } +}; + +class ClassMltD1 : public ClassB, public InterfaceB, public InterfaceC { + public: + char d1[11]; + virtual void f() { } + virtual void A() { } + virtual void B() { } + virtual void C() { } +}; + +class ClassMltD2 : public InterfaceA, public InterfaceB, public ClassB { + public: + char d2[15]; + virtual void f() { } + virtual void A() { } + virtual void B() { } +}; + +// to specifically test heap reachability under +// inerface-only multiple inheritance (some use inside-object pointers): +REGISTER_OBJ_MAKER(MltD1, ClassMltD1* p = new (initialized) ClassMltD1;) +REGISTER_OBJ_MAKER(MltD1_as_B, ClassB* p = new (initialized) ClassMltD1;) +REGISTER_OBJ_MAKER(MltD1_as_IA, InterfaceA* p = new (initialized) ClassMltD1;) +REGISTER_OBJ_MAKER(MltD1_as_IB, InterfaceB* p = new (initialized) ClassMltD1;) +REGISTER_OBJ_MAKER(MltD1_as_IC, InterfaceC* p = new (initialized) ClassMltD1;) + +REGISTER_OBJ_MAKER(MltD2, ClassMltD2* p = new (initialized) ClassMltD2;) +REGISTER_OBJ_MAKER(MltD2_as_B, ClassB* p = new (initialized) ClassMltD2;) +REGISTER_OBJ_MAKER(MltD2_as_IA, InterfaceA* p = new (initialized) ClassMltD2;) +REGISTER_OBJ_MAKER(MltD2_as_IB, InterfaceB* p = new (initialized) ClassMltD2;) + +// to mimic UnicodeString defined in third_party/icu, +// which store a platform-independent-sized refcount in the first +// few bytes and keeps a pointer pointing behind the refcount. +REGISTER_OBJ_MAKER(unicode_string, + char* p = new char[sizeof(uint32) * 10]; + p += sizeof(uint32); +) +// similar, but for platform-dependent-sized refcount +REGISTER_OBJ_MAKER(ref_counted, + char* p = new char[sizeof(int) * 20]; + p += sizeof(int); +) + +struct Nesting { + struct Inner { + Nesting* parent; + Inner(Nesting* p) : parent(p) {} + }; + Inner i0; + char n1[5]; + Inner i1; + char n2[11]; + Inner i2; + char n3[27]; + Inner i3; + Nesting() : i0(this), i1(this), i2(this), i3(this) {} +}; + +// to test inside-object pointers pointing at objects nested into heap objects: +REGISTER_OBJ_MAKER(nesting_i0, Nesting::Inner* p = &((new Nesting())->i0);) +REGISTER_OBJ_MAKER(nesting_i1, Nesting::Inner* p = &((new Nesting())->i1);) +REGISTER_OBJ_MAKER(nesting_i2, Nesting::Inner* p = &((new Nesting())->i2);) +REGISTER_OBJ_MAKER(nesting_i3, Nesting::Inner* p = &((new Nesting())->i3);) // allocate many objects reachable from global data static void TestHeapLeakCheckerLiveness() { - live_leak_b = new(initialized) ClassB; - live_leak_d1 = new(initialized) ClassD1; - live_leak_d2 = new(initialized) ClassD2; - live_leak_d = new(initialized) ClassD; - - live_leak_b_d1 = new(initialized) ClassD1; - live_leak_b2_d2 = new(initialized) ClassD2; - live_leak_b_d = new(initialized) ClassD; - live_leak_b2_d = new(initialized) ClassD; - - live_leak_d1_d = new(initialized) ClassD; - live_leak_d2_d = new(initialized) ClassD; - - HeapLeakChecker::IgnoreObject((ClassD*)live_leak_b2_d); - HeapLeakChecker::IgnoreObject((ClassD*)live_leak_d2_d); - // These two do not get deleted with liveness flood - // because the base class pointer points inside of the objects - // in such cases of multiple inheritance. - // Luckily google code does not use multiple inheritance almost at all. - - live_leak = new(initialized) Array(); - delete [] live_leak3; - live_leak3 = new(initialized) int[33]; - live_leak2->append(*live_leak); - live_leak7.ptr = new(initialized) char[77]; - live_leak8.ptr = new(initialized) Array(); - live_leak8.val = Array(); - - IgnoredLeaks(); - IgnoredLeaks(); - IgnoredLeaks(); + live_leak_mutable.ptr = new(initialized) char[77]; + live_leak_templ_mutable.ptr = new(initialized) Array(); + live_leak_templ_mutable.val = Array(); + + TestObjMakers(); } -DECLARE_string(heap_check); +// ========================================================================= // // Get address (PC value) following the mmap call into addr_after_mmap_call static void* Mmapper(uintptr_t* addr_after_mmap_call) { @@ -1294,6 +1417,8 @@ extern void VerifyHeapProfileTableStackGet() { free(addr); } +// ========================================================================= // + // Helper to do 'return 0;' inside main(): insted we do 'return Pass();' static int Pass() { fprintf(stdout, "PASS\n"); @@ -1362,6 +1487,13 @@ int main(int argc, char** argv) { // (when !FLAGS_test_cancel_global_check) } + if (FLAGS_test_register_leak) { + // make us fail only where the .sh test expects: + Pause(); + for (int i = 0; i < 20; ++i) CHECK(HeapLeakChecker::NoGlobalLeaks()); + return Pass(); + } + TestHeapLeakCheckerLiveness(); HeapLeakChecker heap_check("all"); @@ -1441,10 +1573,6 @@ int main(int argc, char** argv) { range_disable_named = true; ThreadNamedDisabledLeaks(); - HeapLeakChecker::IgnoreObject(new(initialized) set(data, data + 13)); - // This checks both that IgnoreObject works, and - // and the fact that we don't drop such leaks as live for some reason. - CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good return Pass(); diff --git a/src/tests/profiler_unittest.cc b/src/tests/profiler_unittest.cc index e5729a1..1063751 100644 --- a/src/tests/profiler_unittest.cc +++ b/src/tests/profiler_unittest.cc @@ -42,7 +42,7 @@ #endif #include // for wait() #include "google/profiler.h" -#include "base/mutex.h" +#include "base/simple_mutex.h" #include "tests/testutil.h" static int result = 0; diff --git a/src/tests/stacktrace_unittest.cc b/src/tests/stacktrace_unittest.cc index 710743d..6bd28a2 100644 --- a/src/tests/stacktrace_unittest.cc +++ b/src/tests/stacktrace_unittest.cc @@ -39,7 +39,7 @@ // Obtain a backtrace, verify that the expected callers are present in the -// backtrace, and maybe print the backtrace to stdout. +// backtrace, and maybe print the backtrace to stdout. //-----------------------------------------------------------------------// void CheckStackTraceLeaf(); @@ -53,7 +53,7 @@ void CheckStackTrace(int i); // The sequence of functions whose return addresses we expect to see in the // backtrace. const int BACKTRACE_STEPS = 6; -void * expected_stack[BACKTRACE_STEPS] = { +void * expected_stack[BACKTRACE_STEPS] = { (void *) &CheckStackTraceLeaf, (void *) &CheckStackTrace4, (void *) &CheckStackTrace3, @@ -81,11 +81,12 @@ void * expected_stack[BACKTRACE_STEPS] = { //-----------------------------------------------------------------------// +const int kMaxFnLen = 0x40; // assume relevant functions are only this long + void CheckRetAddrIsInFunction( void * ret_addr, void * function_start_addr) { - const int typ_fn_len = 0x40; // assume relevant functions are only 0x40 bytes long CHECK_GE(ret_addr, function_start_addr); - CHECK_LE(ret_addr, (void *) ((char *) function_start_addr + typ_fn_len)); + CHECK_LE(ret_addr, (void *) ((char *) function_start_addr + kMaxFnLen)); } //-----------------------------------------------------------------------// @@ -111,7 +112,11 @@ void CheckStackTraceLeaf(void) { #endif for (int i = 0; i < BACKTRACE_STEPS; i++) { + printf("Backtrace %d: expected: %p..%p actual: %p ... ", + i, expected_stack[i], + reinterpret_cast(expected_stack[i]) + kMaxFnLen, stack[i]); CheckRetAddrIsInFunction(stack[i], expected_stack[i]); + printf("OK\n"); } } diff --git a/src/tests/tcmalloc_unittest.cc b/src/tests/tcmalloc_unittest.cc index e818a21..d3df596 100644 --- a/src/tests/tcmalloc_unittest.cc +++ b/src/tests/tcmalloc_unittest.cc @@ -76,7 +76,7 @@ #include #include #include "base/logging.h" -#include "base/mutex.h" +#include "base/simple_mutex.h" #include "google/malloc_hook.h" #include "google/malloc_extension.h" #include "tests/testutil.h" -- cgit v1.2.1