malloc_debug: reset TrackData mutex after fork

Add a pthread_atfork handler to malloc_debug to lock the TrackData mutex
during fork and reset it in the child.  Ensures that the TrackData is
consistent when forking from a multi-threaded process, and that the
mutex is in a defined state in the child.

Change-Id: I0dfed30045a28551217ceac227d33b2e18894932
This commit is contained in:
Colin Cross 2016-02-07 22:51:15 -08:00
parent 9750a77b31
commit 7a28a3cf1f
4 changed files with 51 additions and 0 deletions

View file

@ -82,3 +82,21 @@ bool DebugData::Initialize() {
}
return true;
}
void DebugData::PrepareFork() {
if (track != nullptr) {
track->PrepareFork();
}
}
void DebugData::PostForkParent() {
if (track != nullptr) {
track->PostForkParent();
}
}
void DebugData::PostForkChild() {
if (track != nullptr) {
track->PostForkChild();
}
}

View file

@ -82,6 +82,10 @@ class DebugData {
bool need_header() { return need_header_; }
size_t extra_bytes() { return extra_bytes_; }
void PrepareFork();
void PostForkParent();
void PostForkChild();
std::unique_ptr<BacktraceData> backtrace;
std::unique_ptr<TrackData> track;
std::unique_ptr<FrontGuardData> front_guard;

View file

@ -58,6 +58,10 @@ class TrackData {
void DisplayLeaks(DebugData& debug);
void PrepareFork() { pthread_mutex_lock(&mutex_); }
void PostForkParent() { pthread_mutex_unlock(&mutex_); }
void PostForkChild() { pthread_mutex_init(&mutex_, NULL); }
private:
pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
std::unordered_set<Header*> headers_;

View file

@ -84,6 +84,28 @@ void* debug_valloc(size_t size);
__END_DECLS
// ------------------------------------------------------------------------
static void InitAtfork() {
static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
pthread_once(&atfork_init, [](){
pthread_atfork(
[](){
if (g_debug != nullptr) {
g_debug->PrepareFork();
}
},
[](){
if (g_debug != nullptr) {
g_debug->PostForkParent();
}
},
[](){
if (g_debug != nullptr) {
g_debug->PostForkChild();
}
}
);
});
}
static void LogTagError(const Header* header, const void* pointer, const char* name) {
ScopedDisableDebugCalls disable;
@ -155,6 +177,9 @@ bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_
if (malloc_zygote_child == nullptr) {
return false;
}
InitAtfork();
g_malloc_zygote_child = malloc_zygote_child;
g_dispatch = malloc_dispatch;