mac handler: Record a file-limits annotation (temporarily)

The "file-limit" annotation will be used to confirm the theory that
certain crashes are caused by systems at or near their file descriptor
table size limits.

The annotation records the system-wide kern.num_files and kern.maxfiles
values, and the process-specific current and maximum file descriptor
limits.

The annotation will be set on crashpad_handler startup, and will be
refreshed every time an exception is handled and every time the upload
thread processes a pending report.

It’s expected that this annotation will be removed after enough data has
been collected to confirm the theory. However, the principle is useful
enough that we may want to provide this feature more generally under
bugs 19 or 21.

Bug: crashpad:180
Change-Id: I3bb78fae60e0567bc4ac2625716e0abe0ddae08c
Reviewed-on: https://chromium-review.googlesource.com/479914
Reviewed-by: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
Mark Mentovai 2017-04-18 11:50:39 -04:00
parent ddcc74f08f
commit b8aaa22905
6 changed files with 146 additions and 0 deletions

View File

@ -35,6 +35,10 @@
#include "util/net/http_transport.h"
#include "util/stdlib/map_insert.h"
#if defined(OS_MACOSX)
#include "handler/mac/file_limit_annotation.h"
#endif // OS_MACOSX
namespace crashpad {
namespace {
@ -228,6 +232,10 @@ void CrashReportUploadThread::ProcessPendingReports() {
void CrashReportUploadThread::ProcessPendingReport(
const CrashReportDatabase::Report& report) {
#if defined(OS_MACOSX)
RecordFileLimitAnnotation();
#endif // OS_MACOSX
Settings* const settings = database_->GetSettings();
bool uploads_enabled;

View File

@ -43,6 +43,8 @@
'mac/crash_report_exception_handler.h',
'mac/exception_handler_server.cc',
'mac/exception_handler_server.h',
'mac/file_limit_annotation.cc',
'mac/file_limit_annotation.h',
'prune_crash_reports_thread.cc',
'prune_crash_reports_thread.h',
'user_stream_data_source.cc',

View File

@ -61,6 +61,7 @@
#include "base/mac/scoped_mach_port.h"
#include "handler/mac/crash_report_exception_handler.h"
#include "handler/mac/exception_handler_server.h"
#include "handler/mac/file_limit_annotation.h"
#include "util/mach/child_port_handshake.h"
#include "util/mach/mach_extensions.h"
#include "util/posix/close_stdio.h"
@ -697,6 +698,8 @@ int HandlerMain(int argc,
reset_sigterm.reset(&old_sigterm_action);
}
}
RecordFileLimitAnnotation();
#elif defined(OS_WIN)
// Shut down as late as possible relative to programs we're watching.
if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY))

View File

@ -21,6 +21,7 @@
#include "base/mac/scoped_mach_port.h"
#include "base/strings/stringprintf.h"
#include "client/settings.h"
#include "handler/mac/file_limit_annotation.h"
#include "minidump/minidump_file_writer.h"
#include "minidump/minidump_user_extension_stream_data_source.h"
#include "snapshot/crashpad_info_client_options.h"
@ -67,6 +68,7 @@ kern_return_t CrashReportExceptionHandler::CatchMachException(
mach_msg_type_number_t* new_state_count,
const mach_msg_trailer_t* trailer,
bool* destroy_complex_request) {
RecordFileLimitAnnotation();
Metrics::ExceptionEncountered();
Metrics::ExceptionCode(ExceptionCodeForMetrics(exception, code[0]));
*destroy_complex_request = true;

View File

@ -0,0 +1,93 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// 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 "handler/mac/file_limit_annotation.h"
#include <errno.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <string>
#include "base/format_macros.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "client/crashpad_info.h"
#include "client/simple_string_dictionary.h"
namespace {
// rv is the return value from sysctl() or sysctlbyname(), and value and size
// are the pointers passed as oldp and oldlenp. If sysctl() failed, the returned
// string will be "E" followed by the error number. If there was a size
// mismatch, the returned string will be "Z" followed by the size indicated by
// sysctl(). Normally, a string representation of *value will be returned.
std::string FormatFromSysctl(int rv, const int* value, const size_t* size) {
if (rv != 0) {
return base::StringPrintf("E%d", errno);
}
if (*size != sizeof(*value)) {
return base::StringPrintf("Z%zu", *size);
}
return base::StringPrintf("%d", *value);
}
// Returns a string for |limit|, or "inf" if |limit| is RLIM_INFINITY.
std::string StringForRLim(rlim_t limit) {
if (limit == RLIM_INFINITY) {
return std::string("inf");
}
return base::StringPrintf("%" PRIu64, limit);
}
} // namespace
namespace crashpad {
void RecordFileLimitAnnotation() {
CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo();
SimpleStringDictionary* simple_annotations =
crashpad_info->simple_annotations();
if (!simple_annotations) {
simple_annotations = new SimpleStringDictionary();
crashpad_info->set_simple_annotations(simple_annotations);
}
int value;
size_t size = sizeof(value);
std::string num_files = FormatFromSysctl(
sysctlbyname("kern.num_files", &value, &size, nullptr, 0), &value, &size);
int mib[] = {CTL_KERN, KERN_MAXFILES};
size = sizeof(value);
std::string max_files = FormatFromSysctl(
sysctl(mib, arraysize(mib), &value, &size, nullptr, 0), &value, &size);
rlimit limit;
std::string nofile;
if (getrlimit(RLIMIT_NOFILE, &limit) != 0) {
nofile = base::StringPrintf("E%d,E%d", errno, errno);
} else {
nofile =
StringForRLim(limit.rlim_cur) + "," + StringForRLim(limit.rlim_max);
}
std::string annotation = base::StringPrintf(
"%s,%s,%s", num_files.c_str(), max_files.c_str(), nofile.c_str());
simple_annotations->SetKeyValue("file-limits", annotation.c_str());
}
} // namespace crashpad

View File

@ -0,0 +1,38 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// 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 CRASHPAD_HANDLER_MAC_FILE_LIMIT_ANNOTATION_H_
#define CRASHPAD_HANDLER_MAC_FILE_LIMIT_ANNOTATION_H_
namespace crashpad {
//! \brief Records a `"file-limits"` simple annotation for the process.
//!
//! This annotation will be used to confirm the theory that certain crashes are
//! caused by systems at or near their file descriptor table size limits.
//!
//! The format of the annotation is four comma-separated values: the system-wide
//! `kern.num_files` and `kern.maxfiles` values from `sysctl()`, and the
//! process-specific current and maximum file descriptor limits from
//! `getrlimit(RLIMIT_NOFILE, …)`.
//!
//! See https://crashpad.chromium.org/bug/180.
//!
//! TODO(mark): Remove this annotation after sufficient data has been collected
//! for analysis.
void RecordFileLimitAnnotation();
} // namespace crashpad
#endif // CRASHPAD_HANDLER_MAC_FILE_LIMIT_ANNOTATION_H_