update heap-checker_unittest to reach into malloc guts via TestingPortal
This commit is contained in:
parent
d5bd0087c1
commit
02f10c15a5
|
@ -749,7 +749,7 @@ heap-checker-death_unittest.sh$(EXEEXT): $(heap_checker_death_unittest_sh_SOURCE
|
||||||
TESTS += heap-checker_unittest
|
TESTS += heap-checker_unittest
|
||||||
heap_checker_unittest_SOURCES = src/tests/heap-checker_unittest.cc
|
heap_checker_unittest_SOURCES = src/tests/heap-checker_unittest.cc
|
||||||
heap_checker_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS)
|
heap_checker_unittest_LDFLAGS = $(TCMALLOC_FLAGS) $(AM_LDFLAGS)
|
||||||
heap_checker_unittest_LDADD = libtcmalloc.la
|
heap_checker_unittest_LDADD = libtcmalloc.la libcommon.la
|
||||||
|
|
||||||
endif WITH_HEAP_CHECKER
|
endif WITH_HEAP_CHECKER
|
||||||
|
|
||||||
|
@ -815,7 +815,7 @@ TESTS += heap-checker_debug_unittest
|
||||||
heap_checker_debug_unittest_SOURCES = $(heap_checker_unittest_SOURCES)
|
heap_checker_debug_unittest_SOURCES = $(heap_checker_unittest_SOURCES)
|
||||||
heap_checker_debug_unittest_CXXFLAGS = $(heap_checker_unittest_CXXFLAGS)
|
heap_checker_debug_unittest_CXXFLAGS = $(heap_checker_unittest_CXXFLAGS)
|
||||||
heap_checker_debug_unittest_LDFLAGS = $(heap_checker_unittest_LDFLAGS)
|
heap_checker_debug_unittest_LDFLAGS = $(heap_checker_unittest_LDFLAGS)
|
||||||
heap_checker_debug_unittest_LDADD = libtcmalloc_debug.la
|
heap_checker_debug_unittest_LDADD = libtcmalloc_debug.la libcommon.la
|
||||||
|
|
||||||
endif WITH_HEAP_CHECKER
|
endif WITH_HEAP_CHECKER
|
||||||
endif WITH_DEBUGALLOC
|
endif WITH_DEBUGALLOC
|
||||||
|
|
|
@ -59,35 +59,26 @@
|
||||||
// (see the comment in our .h file).
|
// (see the comment in our .h file).
|
||||||
|
|
||||||
#include "config_for_unittests.h"
|
#include "config_for_unittests.h"
|
||||||
#ifdef HAVE_POLL_H
|
|
||||||
#include <poll.h>
|
#include <gperftools/heap-checker.h>
|
||||||
#endif
|
|
||||||
#include <stdint.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h> // errno
|
|
||||||
#ifdef HAVE_UNISTD_H
|
|
||||||
#include <unistd.h> // for sleep(), geteuid()
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_MMAP
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#endif
|
|
||||||
#include <fcntl.h> // for open(), close()
|
|
||||||
#ifdef HAVE_EXECINFO_H
|
|
||||||
#include <execinfo.h> // backtrace
|
#include <execinfo.h> // backtrace
|
||||||
#endif
|
#include <fcntl.h>
|
||||||
#ifdef HAVE_GRP_H
|
|
||||||
#include <grp.h> // getgrent, getgrnam
|
#include <grp.h> // getgrent, getgrnam
|
||||||
#endif
|
#include <poll.h>
|
||||||
#ifdef HAVE_PWD_H
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#endif
|
#include <spawn.h>
|
||||||
#include <spawn.h> // for posix_spawn
|
#include <stdint.h>
|
||||||
#include <sys/wait.h> // waitpid etc
|
#include <stdlib.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream> // for cout
|
#include <iomanip>
|
||||||
#include <iomanip> // for hex
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -95,23 +86,14 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "base/commandlineflags.h"
|
|
||||||
#include "base/googleinit.h"
|
|
||||||
#include "base/logging.h"
|
|
||||||
#include "base/commandlineflags.h"
|
|
||||||
#include "base/linuxthreads.h"
|
|
||||||
#include <gperftools/heap-checker.h>
|
|
||||||
#include "memory_region_map.h"
|
|
||||||
#include <gperftools/malloc_extension.h>
|
#include <gperftools/malloc_extension.h>
|
||||||
#include <gperftools/stacktrace.h>
|
#include <gperftools/stacktrace.h>
|
||||||
|
|
||||||
// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
|
#include "base/commandlineflags.h"
|
||||||
// form of the name instead.
|
#include "base/logging.h"
|
||||||
#ifndef MAP_ANONYMOUS
|
#include "memory_region_map.h"
|
||||||
# define MAP_ANONYMOUS MAP_ANON
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace std;
|
#include "testing_portal.h"
|
||||||
|
|
||||||
// ========================================================================= //
|
// ========================================================================= //
|
||||||
|
|
||||||
|
@ -155,17 +137,18 @@ DEFINE_bool(no_threads,
|
||||||
// This is used so we can make can_create_leaks_reliably true
|
// This is used so we can make can_create_leaks_reliably true
|
||||||
// for any pthread implementation and test with that.
|
// 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)
|
#define WARN_IF(cond, msg) LOG_IF(WARNING, cond, msg)
|
||||||
|
|
||||||
// This is an evil macro! Be very careful using it...
|
// This is an evil macro! Be very careful using it...
|
||||||
#undef VLOG // and we start by evilling overriding logging.h VLOG
|
#undef VLOG // and we start by evilling overriding logging.h VLOG
|
||||||
#define VLOG(lvl) if (FLAGS_verbose >= (lvl)) cout << "\n"
|
#define VLOG(lvl) if (FLAGS_verbose >= (lvl)) std::cout << "\n"
|
||||||
// This is, likewise, evil
|
// This is, likewise, evil
|
||||||
#define LOGF VLOG(INFO)
|
#define LOGF VLOG(INFO)
|
||||||
|
|
||||||
|
std::string_view GetHeapCheckFlag() {
|
||||||
|
return tcmalloc::TestingPortal::Get()->GetHeapCheckFlag();
|
||||||
|
}
|
||||||
|
|
||||||
static void RunHeapBusyThreads(); // below
|
static void RunHeapBusyThreads(); // below
|
||||||
|
|
||||||
|
|
||||||
|
@ -315,7 +298,7 @@ static void UnHide(T** ptr) {
|
||||||
|
|
||||||
static void LogHidden(const char* message, const void* ptr) {
|
static void LogHidden(const char* message, const void* ptr) {
|
||||||
LOGF << message << " : "
|
LOGF << message << " : "
|
||||||
<< ptr << " ^ " << reinterpret_cast<void*>(kHideMask) << endl;
|
<< ptr << " ^ " << reinterpret_cast<void*>(kHideMask) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// volatile to fool the compiler against inlining the calls to these
|
// volatile to fool the compiler against inlining the calls to these
|
||||||
|
@ -717,7 +700,7 @@ static void TestHeapLeakCheckerDisabling() {
|
||||||
CHECK(check.SameHeap());
|
CHECK(check.SameHeap());
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef set<int> IntSet;
|
typedef std::set<int> IntSet;
|
||||||
|
|
||||||
static int some_ints[] = { 1, 2, 3, 21, 22, 23, 24, 25 };
|
static int some_ints[] = { 1, 2, 3, 21, 22, 23, 24, 25 };
|
||||||
|
|
||||||
|
@ -783,7 +766,7 @@ static void TestSTLAllocInverse() {
|
||||||
|
|
||||||
template<class Alloc>
|
template<class Alloc>
|
||||||
static void DirectTestSTLAlloc(Alloc allocator, const char* name) {
|
static void DirectTestSTLAlloc(Alloc allocator, const char* name) {
|
||||||
HeapLeakChecker check((string("direct_stl-") + name).c_str());
|
HeapLeakChecker check((std::string("direct_stl-") + name).c_str());
|
||||||
static const int kSize = 1000;
|
static const int kSize = 1000;
|
||||||
typename Alloc::value_type* ptrs[kSize];
|
typename Alloc::value_type* ptrs[kSize];
|
||||||
for (int i = 0; i < kSize; ++i) {
|
for (int i = 0; i < kSize; ++i) {
|
||||||
|
@ -841,21 +824,15 @@ static void TestLibCAllocate() {
|
||||||
strerror(errno);
|
strerror(errno);
|
||||||
const time_t now = time(NULL);
|
const time_t now = time(NULL);
|
||||||
ctime(&now);
|
ctime(&now);
|
||||||
#ifdef HAVE_EXECINFO_H
|
|
||||||
void *stack[1];
|
void *stack[1];
|
||||||
backtrace(stack, 1);
|
backtrace(stack, 1);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (grplock.TryLock()) {
|
if (grplock.TryLock()) {
|
||||||
#ifdef HAVE_GRP_H
|
|
||||||
gid_t gid = getgid();
|
gid_t gid = getgid();
|
||||||
getgrgid(gid);
|
getgrgid(gid);
|
||||||
if (grp == NULL) grp = getgrent(); // a race condition here is okay
|
if (grp == NULL) grp = getgrent(); // a race condition here is okay
|
||||||
getgrnam(grp->gr_name);
|
getgrnam(grp->gr_name);
|
||||||
#endif
|
|
||||||
#ifdef HAVE_PWD_H
|
|
||||||
getpwuid(geteuid());
|
getpwuid(geteuid());
|
||||||
#endif
|
|
||||||
grplock.Unlock();
|
grplock.Unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -879,7 +856,7 @@ static void* HeapBusyThreadBody(void* a) {
|
||||||
register int** ptr;
|
register int** ptr;
|
||||||
#endif
|
#endif
|
||||||
ptr = NULL;
|
ptr = NULL;
|
||||||
typedef set<int> Set;
|
typedef std::set<int> Set;
|
||||||
Set s1;
|
Set s1;
|
||||||
while (1) {
|
while (1) {
|
||||||
// TestLibCAllocate() calls libc functions that don't work so well
|
// TestLibCAllocate() calls libc functions that don't work so well
|
||||||
|
@ -891,7 +868,7 @@ static void* HeapBusyThreadBody(void* a) {
|
||||||
ptr = new(initialized) int*[1];
|
ptr = new(initialized) int*[1];
|
||||||
*ptr = new(initialized) int[1];
|
*ptr = new(initialized) int[1];
|
||||||
}
|
}
|
||||||
set<int>* s2 = new(initialized) set<int>[1];
|
std::set<int>* s2 = new(initialized) std::set<int>[1];
|
||||||
s1.insert(random());
|
s1.insert(random());
|
||||||
s2->insert(*s1.begin());
|
s2->insert(*s1.begin());
|
||||||
user += *s2->begin();
|
user += *s2->begin();
|
||||||
|
@ -973,7 +950,7 @@ static void RunHeapBusyThreads() {
|
||||||
// returns a "weird" pointer to a new object for which
|
// returns a "weird" pointer to a new object for which
|
||||||
// it's worth checking that the object is reachable via that pointer.
|
// it's worth checking that the object is reachable via that pointer.
|
||||||
typedef void* (*ObjMakerFunc)();
|
typedef void* (*ObjMakerFunc)();
|
||||||
static list<ObjMakerFunc> obj_makers; // list of registered object makers
|
static std::list<ObjMakerFunc> obj_makers; // list of registered object makers
|
||||||
|
|
||||||
// Helper macro to register an object making function
|
// Helper macro to register an object making function
|
||||||
// 'name' is an identifier of this object maker,
|
// 'name' is an identifier of this object maker,
|
||||||
|
@ -995,7 +972,7 @@ struct ObjMakerRegistrar {
|
||||||
|
|
||||||
// List of the objects/pointers made with all the obj_makers
|
// List of the objects/pointers made with all the obj_makers
|
||||||
// to test reachability via global data pointers during leak checks.
|
// to test reachability via global data pointers during leak checks.
|
||||||
static list<void*>* live_objects = new list<void*>;
|
static std::list<void*>* live_objects = new std::list<void*>;
|
||||||
// pointer so that it does not get destructed on exit
|
// pointer so that it does not get destructed on exit
|
||||||
|
|
||||||
// Exerciser for one ObjMakerFunc.
|
// Exerciser for one ObjMakerFunc.
|
||||||
|
@ -1012,7 +989,7 @@ static void TestPointerReach(ObjMakerFunc obj_maker) {
|
||||||
|
|
||||||
// Test all ObjMakerFunc registred via REGISTER_OBJ_MAKER.
|
// Test all ObjMakerFunc registred via REGISTER_OBJ_MAKER.
|
||||||
static void TestObjMakers() {
|
static void TestObjMakers() {
|
||||||
for (list<ObjMakerFunc>::const_iterator i = obj_makers.begin();
|
for (std::list<ObjMakerFunc>::const_iterator i = obj_makers.begin();
|
||||||
i != obj_makers.end(); ++i) {
|
i != obj_makers.end(); ++i) {
|
||||||
TestPointerReach(*i);
|
TestPointerReach(*i);
|
||||||
TestPointerReach(*i); // a couple more times would not hurt
|
TestPointerReach(*i); // a couple more times would not hurt
|
||||||
|
@ -1086,11 +1063,12 @@ REGISTER_OBJ_MAKER(3_sized, void* p = malloc(3);)
|
||||||
REGISTER_OBJ_MAKER(4_sized, void* p = malloc(4);)
|
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 int set_data[] = { 1, 2, 3, 4, 5, 6, 7, 21, 22, 23, 24, 25, 26, 27 };
|
||||||
static set<int> live_leak_set(set_data, set_data+7);
|
static std::set<int> live_leak_set(set_data, set_data+7);
|
||||||
static const set<int> live_leak_const_set(set_data, set_data+14);
|
static const std::set<int> live_leak_const_set(set_data, set_data+14);
|
||||||
|
|
||||||
REGISTER_OBJ_MAKER(set,
|
REGISTER_OBJ_MAKER(
|
||||||
set<int>* p = new(initialized) set<int>(set_data, set_data + 13);
|
set,
|
||||||
|
std::set<int>* p = new(initialized) std::set<int>(set_data, set_data + 13);
|
||||||
)
|
)
|
||||||
|
|
||||||
class ClassA {
|
class ClassA {
|
||||||
|
@ -1309,16 +1287,14 @@ static void VerifyMemoryRegionMapStackGet() {
|
||||||
uintptr_t caller_addr_limit;
|
uintptr_t caller_addr_limit;
|
||||||
void* addr = (*mmapper_addr)(&caller_addr_limit);
|
void* addr = (*mmapper_addr)(&caller_addr_limit);
|
||||||
uintptr_t caller = 0;
|
uintptr_t caller = 0;
|
||||||
{ MemoryRegionMap::LockHolder l;
|
tcmalloc::TestingPortal::Get()->IterateMemoryRegionMap(
|
||||||
for (MemoryRegionMap::RegionIterator
|
[&] (const void* _region) {
|
||||||
i = MemoryRegionMap::BeginRegionLocked();
|
const MemoryRegionMap::Region* region = static_cast<const MemoryRegionMap::Region*>(_region);
|
||||||
i != MemoryRegionMap::EndRegionLocked(); ++i) {
|
if (region->start_addr == reinterpret_cast<uintptr_t>(addr)) {
|
||||||
if (i->start_addr == reinterpret_cast<uintptr_t>(addr)) {
|
|
||||||
CHECK_EQ(caller, 0);
|
CHECK_EQ(caller, 0);
|
||||||
caller = i->caller();
|
caller = region->caller();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
// caller must point into Mmapper function:
|
// caller must point into Mmapper function:
|
||||||
if (!(GetFunctionAddress(mmapper_addr) <= caller &&
|
if (!(GetFunctionAddress(mmapper_addr) <= caller &&
|
||||||
caller < caller_addr_limit)) {
|
caller < caller_addr_limit)) {
|
||||||
|
@ -1423,7 +1399,7 @@ int main(int argc, char** argv) {
|
||||||
run_hidden_ptr = DoRunHidden;
|
run_hidden_ptr = DoRunHidden;
|
||||||
wipe_stack_ptr = DoWipeStack;
|
wipe_stack_ptr = DoWipeStack;
|
||||||
if (!HeapLeakChecker::IsActive()) {
|
if (!HeapLeakChecker::IsActive()) {
|
||||||
CHECK_EQ(FLAGS_heap_check, "");
|
CHECK_EQ(GetHeapCheckFlag(), "");
|
||||||
LOG(WARNING, "HeapLeakChecker got turned off; we won't test much...");
|
LOG(WARNING, "HeapLeakChecker got turned off; we won't test much...");
|
||||||
} else {
|
} else {
|
||||||
VerifyMemoryRegionMapStackGet();
|
VerifyMemoryRegionMapStackGet();
|
||||||
|
@ -1449,7 +1425,7 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
TestLibCAllocate();
|
TestLibCAllocate();
|
||||||
|
|
||||||
LOGF << "In main(): heap_check=" << FLAGS_heap_check << endl;
|
LOGF << "In main(): heap_check=" << GetHeapCheckFlag() << std::endl;
|
||||||
|
|
||||||
CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good
|
CHECK(HeapLeakChecker::NoGlobalLeaks()); // so far, so good
|
||||||
|
|
||||||
|
@ -1550,14 +1526,14 @@ int main(int argc, char** argv) {
|
||||||
DTSL(std::allocator<char>());
|
DTSL(std::allocator<char>());
|
||||||
DTSL(std::allocator<int>());
|
DTSL(std::allocator<int>());
|
||||||
DTSL(std::string().get_allocator());
|
DTSL(std::string().get_allocator());
|
||||||
DTSL(string().get_allocator());
|
DTSL(std::string().get_allocator());
|
||||||
DTSL(vector<int>().get_allocator());
|
DTSL(std::vector<int>().get_allocator());
|
||||||
DTSL(vector<double>().get_allocator());
|
DTSL(std::vector<double>().get_allocator());
|
||||||
DTSL(vector<vector<int> >().get_allocator());
|
DTSL(std::vector<std::vector<int> >().get_allocator());
|
||||||
DTSL(vector<string>().get_allocator());
|
DTSL(std::vector<std::string>().get_allocator());
|
||||||
DTSL((map<string, string>().get_allocator()));
|
DTSL((std::map<std::string, std::string>().get_allocator()));
|
||||||
DTSL((map<string, int>().get_allocator()));
|
DTSL((std::map<std::string, int>().get_allocator()));
|
||||||
DTSL(set<char>().get_allocator());
|
DTSL(std::set<char>().get_allocator());
|
||||||
#undef DTSL
|
#undef DTSL
|
||||||
|
|
||||||
TestLibCAllocate();
|
TestLibCAllocate();
|
||||||
|
|
Loading…
Reference in New Issue