Valgrind is complaining about use of uninitialized memory in
absl::GetStackTrace, and the cases where it complains the backtraces are
incomplete. Note: this means that jemalloc heap profiling no longer
works out of the box. Advanced users who want to enable jemalloc heap
profiling will now have to revert this change and build from source.
This commit is contained in:
Andrew Noyes 2022-09-06 16:55:18 -07:00
parent b361bd8e7a
commit fbf5830bb2
5 changed files with 98 additions and 6 deletions

View File

@ -22,6 +22,7 @@
#include "fmt/format.h"
#include "fdbserver/workloads/workloads.actor.h"
#include "flow/SignalSafeUnwind.h"
#include "flow/actorcompiler.h" // This must be the last #include.
// Stress test the slow task profiler or flow profiler
@ -42,22 +43,24 @@ struct SlowTaskWorkload : TestWorkload {
ACTOR static Future<Void> go() {
wait(delay(1));
int64_t phc = dl_iterate_phdr_calls;
int64_t startProfilesDeferred = getNumProfilesDeferred();
int64_t startProfilesOverflowed = getNumProfilesOverflowed();
int64_t startProfilesCaptured = getNumProfilesCaptured();
int64_t exc = 0;
fprintf(stdout, "Slow task starting\n");
fprintf(stderr, "Slow task starting\n");
for (int i = 0; i < 10; i++) {
fprintf(stdout, " %d\n", i);
fprintf(stderr, " %d\n", i);
double end = timer() + 1;
while (timer() < end) {
do_slow_exception_thing(&exc);
}
}
fmt::print(stdout,
"Slow task complete: {0} exceptions; {1} profiles deferred, {2} profiles overflowed, {3} profiles "
"captured\n",
fmt::print(stderr,
"Slow task complete: {0} exceptions; {1} calls to dl_iterate_phdr, {2}"
" profiles deferred, {3} profiles overflowed, {4} profiles captured\n",
exc,
dl_iterate_phdr_calls - phc,
getNumProfilesDeferred() - startProfilesDeferred,
getNumProfilesOverflowed() - startProfilesOverflowed,
getNumProfilesCaptured() - startProfilesCaptured);

View File

@ -90,6 +90,10 @@ void initProfiling() {
net2backtraces = new volatile void*[net2backtraces_max];
other_backtraces = new volatile void*[net2backtraces_max];
// According to folk wisdom, calling this once before setting up the signal handler makes
// it async signal safe in practice :-/
backtrace(const_cast<void**>(other_backtraces), net2backtraces_max);
sigemptyset(&sigprof_set);
sigaddset(&sigprof_set, SIGPROF);
}

View File

@ -3765,7 +3765,7 @@ void profileHandler(int sig) {
ps->timestamp = checkThreadTime.is_lock_free() ? checkThreadTime.load() : 0;
// SOMEDAY: should we limit the maximum number of frames from backtrace beyond just available space?
size_t size = platform::raw_backtrace(ps->frames, net2backtraces_max - net2backtraces_offset - 2);
size_t size = backtrace(ps->frames, net2backtraces_max - net2backtraces_offset - 2);
ps->length = size;

55
flow/SignalSafeUnwind.cpp Normal file
View File

@ -0,0 +1,55 @@
/*
* SignalSafeUnwind.cpp
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flow/SignalSafeUnwind.h"
int64_t dl_iterate_phdr_calls = 0;
#if defined(__linux__) && !defined(USE_SANITIZER)
#include <link.h>
#include <mutex>
static int (*chain_dl_iterate_phdr)(int (*callback)(struct dl_phdr_info* info, size_t size, void* data),
void* data) = nullptr;
static void initChain() {
static std::once_flag flag;
// Ensure that chain_dl_iterate_phdr points to the "real" function that we are overriding
std::call_once(flag, []() { *(void**)&chain_dl_iterate_phdr = dlsym(RTLD_NEXT, "dl_iterate_phdr"); });
if (!chain_dl_iterate_phdr) {
criticalError(FDB_EXIT_ERROR, "SignalSafeUnwindError", "Unable to find dl_iterate_phdr symbol");
}
}
// This overrides the function in libc!
extern "C" int dl_iterate_phdr(int (*callback)(struct dl_phdr_info* info, size_t size, void* data), void* data) {
interlockedIncrement64(&dl_iterate_phdr_calls);
initChain();
setProfilingEnabled(0);
int result = chain_dl_iterate_phdr(callback, data);
setProfilingEnabled(1);
return result;
}
#endif

View File

@ -0,0 +1,30 @@
/*
* SignalSafeUnwind.h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLOW_SIGNAL_SAFE_UNWIND
#define FLOW_SIGNAL_SAFE_UNWIND
#pragma once
#include "flow/Platform.h"
// This can be used by tests to measure the number of calls to dl_iterate_phdr intercepted
extern int64_t dl_iterate_phdr_calls;
#endif