Commit d2031d30 authored by Wez's avatar Wez Committed by Commit Bot

Flush coverage statistics in process fast-exit & debug-break paths.

Defines a base::debug::WriteClangCoverageProfile() API which performs
an explicit call to __llvm_profile_dump() in CLANG_COVERAGE builds, with
locking to ensure thread-safety.

This API is invoked in the base::debug::BreakDebugger() and
base::Process::TerminateCurrentProcessImmediately() APIs, immediately
prior to them terminating the process, to mirror the coverage-writing
step that would be performed via an at-exit handler during a normal
process-exit.

This ensures that we get as complete coverage data as possible from
processes which fast-terminate/break (e.g. EXPECT_DEATH() sub-processes,
e.g. browser child processes, etc).

Bug: 849369
Change-Id: I38262334bb5abf8d5ba40c2c32352b38096905ec
Reviewed-on: https://chromium-review.googlesource.com/1172932Reviewed-by: default avatarGabriel Charette <gab@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarMax Moroz <mmoroz@chromium.org>
Commit-Queue: Wez <wez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583882}
parent 6e9f5a9f
......@@ -1305,6 +1305,14 @@ jumbo_component("base") {
}
}
if (use_clang_coverage) {
# Call-sites use this conditional on the CLANG_COVERAGE macro, for clarity.
sources += [
"test/clang_coverage.cc",
"test/clang_coverage.h",
]
}
# Allow more direct string conversions on platforms with native utf8
# strings
if (is_mac || is_ios || is_chromeos || is_chromecast || is_fuchsia) {
......
......@@ -18,6 +18,7 @@
#include <vector>
#include "base/macros.h"
#include "base/test/clang_coverage.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
......@@ -246,6 +247,10 @@ void DebugBreak() {
#endif
void BreakDebugger() {
#if defined(CLANG_COVERAGE)
WriteClangCoverageProfile();
#endif
// NOTE: This code MUST be async-signal safe (it's used by in-process
// stack dumping signal handler). NO malloc or stdio is allowed here.
......
......@@ -7,6 +7,8 @@
#include <stdlib.h>
#include <windows.h>
#include "base/test/clang_coverage.h"
namespace base {
namespace debug {
......@@ -15,6 +17,10 @@ bool BeingDebugged() {
}
void BreakDebugger() {
#if defined(CLANG_COVERAGE)
WriteClangCoverageProfile();
#endif
if (IsDebugUISuppressed())
_exit(1);
......
......@@ -12,6 +12,7 @@
#include "base/fuchsia/default_job.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/strings/stringprintf.h"
#include "base/test/clang_coverage.h"
namespace base {
......@@ -88,6 +89,9 @@ bool Process::CanBackgroundProcesses() {
// static
void Process::TerminateCurrentProcessImmediately(int exit_code) {
#if defined(CLANG_COVERAGE)
WriteClangCoverageProfile();
#endif
_exit(exit_code);
}
......
......@@ -15,6 +15,7 @@
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/kill.h"
#include "base/test/clang_coverage.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
......@@ -271,6 +272,9 @@ bool Process::CanBackgroundProcesses() {
// static
void Process::TerminateCurrentProcessImmediately(int exit_code) {
#if defined(CLANG_COVERAGE)
WriteClangCoverageProfile();
#endif
_exit(exit_code);
}
......
......@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/kill.h"
#include "base/test/clang_coverage.h"
#include "base/threading/thread_restrictions.h"
#include <windows.h>
......@@ -85,6 +86,9 @@ bool Process::CanBackgroundProcesses() {
// static
void Process::TerminateCurrentProcessImmediately(int exit_code) {
#if defined(CLANG_COVERAGE)
WriteClangCoverageProfile();
#endif
::TerminateProcess(GetCurrentProcess(), exit_code);
// There is some ambiguity over whether the call above can return. Rather than
// hitting confusing crashes later on we should crash right here.
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/clang_coverage.h"
#include "base/no_destructor.h"
#include "base/synchronization/lock.h"
extern "C" int __llvm_profile_dump(void);
namespace base {
void WriteClangCoverageProfile() {
// __llvm_profile_dump() guarantees that it will not dump coverage information
// if it is being called twice or more. However, it is not thread safe, as it
// is supposed to be called from atexit() handler rather than being called
// directly from random places. Since we have to call it ourselves, we must
// ensure thread safety in order to prevent duplication of coverage counters.
static base::NoDestructor<base::Lock> lock;
base::AutoLock auto_lock(*lock);
__llvm_profile_dump();
}
} // namespace base
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TEST_CLANG_COVERAGE_H_
#define BASE_TEST_CLANG_COVERAGE_H_
namespace base {
// Write out the accumulated code coverage profile to the configured file.
// This is used internally by e.g. base::Process and FATAL logging, to cause
// coverage information to be stored even when performing an "immediate" exit
// (or triggering a debug crash), where the automatic at-exit writer will not
// be invoked.
// This call is thread-safe, and will write profiling data at-most-once.
// Call-sites invoke this API only if the CLANG_COVERAGE macro is defined.
void WriteClangCoverageProfile();
} // namespace base
#endif // BASE_TEST_CLANG_COVERAGE_H_
......@@ -21,7 +21,6 @@
#include "base/message_loop/timer_slack.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/optional.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
......@@ -78,26 +77,9 @@
#include "content/public/common/content_descriptors.h"
#endif
#if defined(CLANG_COVERAGE)
extern "C" int __llvm_profile_dump(void);
#endif
namespace content {
namespace {
void WriteClangCoverageProfile() {
#if defined(CLANG_COVERAGE)
// __llvm_profile_dump() guarantees that it will not dump coverage information
// if it is being called twice or more. However, it is not thread safe, as it
// is supposed to be called from atexit() handler rather than being called
// directly from random places. Since we have to call it ourselves, we must
// ensure thread safety in order to prevent duplication of coverage counters.
static base::NoDestructor<base::Lock> lock;
base::AutoLock auto_lock(*lock);
__llvm_profile_dump();
#endif
}
// How long to wait for a connection to the browser process before giving up.
const int kConnectionTimeoutS = 15;
......@@ -112,8 +94,8 @@ base::LazyInstance<base::ThreadLocalPointer<ChildThreadImpl>>::DestructorAtExit
#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
defined(UNDEFINED_SANITIZER)
// A thread delegate that waits for |duration| and then exits the process with
// _exit(0).
// A thread delegate that waits for |duration| and then exits the process
// immediately, without executing finalizers.
class WaitAndExitDelegate : public base::PlatformThread::Delegate {
public:
explicit WaitAndExitDelegate(base::TimeDelta duration)
......@@ -121,8 +103,7 @@ class WaitAndExitDelegate : public base::PlatformThread::Delegate {
void ThreadMain() override {
base::PlatformThread::Sleep(duration_);
WriteClangCoverageProfile();
_exit(0);
base::Process::TerminateCurrentProcessImmediately(0);
}
private:
......@@ -182,8 +163,7 @@ class SuicideOnChannelErrorFilter : public IPC::MessageFilter {
__lsan_do_leak_check();
#endif
#else
WriteClangCoverageProfile();
_exit(0);
base::Process::TerminateCurrentProcessImmediately(0);
#endif
}
......@@ -649,12 +629,7 @@ ChildThreadImpl::~ChildThreadImpl() {
g_lazy_tls.Pointer()->Set(nullptr);
}
void ChildThreadImpl::Shutdown() {
// The renderer process (and others) can to fast shutdown by calling _exit(0),
// in which case the clang-coverage profile does not get written to the file.
// So force write the profile here before shutting down.
WriteClangCoverageProfile();
}
void ChildThreadImpl::Shutdown() {}
bool ChildThreadImpl::ShouldBeDestroyed() {
return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment