Merge master cd284713834e into doc

This commit is contained in:
Mark Mentovai 2017-02-08 16:22:33 -05:00
commit cea3a3df1f
21 changed files with 600 additions and 185 deletions

12
DEPS
View File

@ -19,13 +19,13 @@ vars = {
deps = {
'buildtools':
Var('chromium_git') + '/chromium/buildtools.git@' +
'f8fc76ea5ce4a60cda2fa5d7df3d4a62935b3113',
'a7cc7a3e21a061975b33dcdcd81a9716ba614c3c',
'crashpad/third_party/gtest/gtest':
Var('chromium_git') + '/external/github.com/google/googletest@' +
'ec44c6c1675c25b9827aacd08c02433cccde7780',
'd62d6c6556d96dda924382547c54a4b3afedb22c',
'crashpad/third_party/gyp/gyp':
Var('chromium_git') + '/external/gyp@' +
'93cc6e2c23e4d5ebd179f388e67aa907d0dfd43d',
'a7055b3989c1074adca03b4b4829e7f0e57f6efd',
# TODO(scottmg): Consider pinning these. For now, we don't have any particular
# reason to do so.
@ -38,7 +38,7 @@ deps = {
'crashpad/third_party/mini_chromium/mini_chromium':
Var('chromium_git') + '/chromium/mini_chromium@' +
'de1afb04f4afc074ec6d23bd9ee7b1e6b365427f',
'f65519e442d23498937251e680a3b113927613b0',
}
hooks = [
@ -100,3 +100,7 @@ hooks = [
'action': ['python', 'crashpad/build/gyp_crashpad.py'],
},
]
recursedeps = [
'buildtools',
]

View File

@ -14,9 +14,11 @@
#include "handler/handler_main.h"
#include <errno.h>
#include <getopt.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <map>
#include <memory>
@ -38,6 +40,8 @@
#include "handler/prune_crash_reports_thread.h"
#include "tools/tool_support.h"
#include "util/file/file_io.h"
#include "util/misc/metrics.h"
#include "util/numeric/in_range_cast.h"
#include "util/stdlib/map_insert.h"
#include "util/stdlib/string_number_conversion.h"
#include "util/string/split_string.h"
@ -105,6 +109,122 @@ void Usage(const base::FilePath& me) {
#if defined(OS_MACOSX)
struct sigaction g_original_crash_sigaction[NSIG];
void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) {
// Is siginfo->si_code useful? The only interesting values on macOS are 0 (not
// useful, signals generated asynchronously such as by kill() or raise()) and
// small positive numbers (useful, signal generated via a hardware fault). The
// standard specifies these other constants, and while xnu never uses them,
// they are intended to denote signals generated asynchronously and are
// included here. Additionally, existing practice on other systems
// (acknowledged by the standard) is for negative numbers to indicate that a
// signal was generated asynchronously. Although xnu does not do this, allow
// for the possibility for completeness.
bool si_code_valid = !(siginfo->si_code <= 0 ||
siginfo->si_code == SI_USER ||
siginfo->si_code == SI_QUEUE ||
siginfo->si_code == SI_TIMER ||
siginfo->si_code == SI_ASYNCIO ||
siginfo->si_code == SI_MESGQ);
// 0x5343 = 'SC', signifying “signal and code”, disambiguates from the schema
// used by ExceptionCodeForMetrics(). That system primarily uses Mach
// exception types and codes, which are not available to a POSIX signal
// handler. It does provide a way to encode only signal numbers, but does so
// with the understanding that certain “raw” signals would not be encountered
// without a Mach exception. Furthermore, it does not allow siginfo->si_code
// to be encoded, because thats not available to Mach exception handlers. It
// would be a shame to lose that information available to a POSIX signal
// handler.
int metrics_code = 0x53430000 | (InRangeCast<uint8_t>(sig, 0xff) << 8);
if (si_code_valid) {
metrics_code |= InRangeCast<uint8_t>(siginfo->si_code, 0xff);
}
Metrics::HandlerCrashed(metrics_code);
// Restore the previous signal handler.
DCHECK_GT(sig, 0);
DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction));
struct sigaction* osa = &g_original_crash_sigaction[sig];
int rv = sigaction(sig, osa, nullptr);
DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig;
// If the signal was received synchronously resulting from a hardware fault,
// returning from the signal handler will cause the kernel to re-raise it,
// because this handler hasnt done anything to alleviate the condition that
// caused the signal to be raised in the first place. With the old signal
// handler in place (expected to be SIG_DFL), it will cause the same behavior
// to be taken as though this signal handler had never been installed at all
// (expected to be a crash). This is ideal, because the signal is re-raised
// with the same properties and from the same context that initially triggered
// it, providing the best debugging experience.
if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) ||
!si_code_valid) {
// Signals received other than via hardware faults, such as those raised
// asynchronously via kill() and raise(), and those arising via hardware
// traps such as int3 (resulting in SIGTRAP but advancing the instruction
// pointer), will not reoccur on their own when returning from the signal
// handler. Re-raise them or call to the previous signal handler as
// appropriate.
//
// Unfortunately, when SIGBUS is received asynchronously via kill(),
// siginfo->si_code makes it appear as though it was actually received via a
// hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c
// sendsig(). An asynchronous SIGBUS will thus cause the handler-crashed
// metric to be logged but will not cause the process to terminate. This
// isnt ideal, but asynchronous SIGBUS is an unexpected condition. The
// alternative, to re-raise here on any SIGBUS, is a bad idea because it
// would lose properties associated with the the original signal, which are
// very valuable for debugging and are visible to a Mach exception handler.
// Since SIGBUS is normally received synchronously in response to a hardware
// fault, dont sweat the unexpected asynchronous case.
if (osa->sa_handler == SIG_DFL) {
// Because this signal handler executes with the signal blocked, this
// raise() cannot immediately deliver the signal. Delivery is deferred
// until this signal handler returns and the signal becomes unblocked. The
// re-raised signal will appear with the same context as where it was
// initially triggered.
rv = raise(sig);
DPLOG_IF(ERROR, rv != 0) << "raise";
} else if (osa->sa_handler != SIG_IGN) {
if (osa->sa_flags & SA_SIGINFO) {
osa->sa_sigaction(sig, siginfo, context);
} else {
osa->sa_handler(sig);
}
}
}
}
void InstallCrashHandler() {
struct sigaction sa = {};
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = HandleCrashSignal;
// These are the core-generating signals from 10.12.3
// xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the
// set.
const int kSignals[] = {SIGQUIT,
SIGILL,
SIGTRAP,
SIGABRT,
SIGEMT,
SIGFPE,
SIGBUS,
SIGSEGV,
SIGSYS};
for (int sig : kSignals) {
DCHECK_GT(sig, 0);
DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction));
int rv = sigaction(sig, &sa, &g_original_crash_sigaction[sig]);
PCHECK(rv == 0) << "sigaction " << sig;
}
}
struct ResetSIGTERMTraits {
static struct sigaction* InvalidValue() {
return nullptr;
@ -126,9 +246,8 @@ void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) {
g_exception_handler_server->Stop();
}
#endif // OS_MACOSX
#elif defined(OS_WIN)
#if defined(OS_WIN)
LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr;
LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
@ -139,15 +258,18 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
else
return EXCEPTION_CONTINUE_SEARCH;
}
#endif // OS_WIN
void InstallCrashHandler() {
g_original_exception_filter =
SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
}
#endif // OS_MACOSX
} // namespace
int HandlerMain(int argc, char* argv[]) {
#if defined(OS_WIN)
g_original_exception_filter =
SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
#endif
InstallCrashHandler();
const base::FilePath argv0(
ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));

View File

@ -17,7 +17,6 @@
#include <string>
#include "base/logging.h"
#include "base/stl_util.h"
#include "minidump/minidump_extensions.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"
@ -29,7 +28,8 @@ MinidumpHandleDataWriter::MinidumpHandleDataWriter()
}
MinidumpHandleDataWriter::~MinidumpHandleDataWriter() {
base::STLDeleteContainerPairSecondPointers(strings_.begin(), strings_.end());
for (auto& item : strings_)
delete item.second;
}
void MinidumpHandleDataWriter::InitializeFromSnapshot(

View File

@ -18,7 +18,6 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"
@ -100,7 +99,8 @@ MinidumpSimpleStringDictionaryWriter::MinidumpSimpleStringDictionaryWriter()
}
MinidumpSimpleStringDictionaryWriter::~MinidumpSimpleStringDictionaryWriter() {
base::STLDeleteContainerPairSecondPointers(entries_.begin(), entries_.end());
for (auto& item : entries_)
delete item.second;
}
void MinidumpSimpleStringDictionaryWriter::InitializeFromMap(

View File

@ -27,13 +27,21 @@ namespace crashpad {
namespace process_types {
namespace internal {
// Some structure definitions have tail padding when built in a 64-bit
// environment, but will have less (or no) tail padding in a 32-bit environment.
// These structures apparent sizes will differ between these two environments,
// which is incorrect. Use this “Nothing” type to place an “end” marker after
// all of the real members of such structures, and use offsetof(type, end) to
// compute their actual sizes.
using Nothing = char[0];
// Some structure definitions differ in 32-bit and 64-bit environments by having
// additional “reserved” padding fields present only in the 64-bit environment.
// These Reserved*_64Only* types allow the process_types system to replicate
// these structures more precisely.
using Reserved32_64Only32 = char[0];
using Reserved32_64Only32 = Nothing;
using Reserved32_64Only64 = uint32_t;
using Reserved64_64Only32 = char[0];
using Reserved64_64Only32 = Nothing;
using Reserved64_64Only64 = uint64_t;
} // namespace internal
@ -65,6 +73,7 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
using UIntPtr = internal::TraitsGeneric::UIntPtr; \
using Reserved32_64Only = internal::TraitsGeneric::Reserved32_64Only; \
using Reserved64_64Only = internal::TraitsGeneric::Reserved64_64Only; \
using Nothing = internal::TraitsGeneric::Nothing; \
\
/* Initializes an object with data read from |process_reader| at \
* |address|, properly genericized. */ \
@ -88,7 +97,7 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
/* Similar to Size(), but computes the expected size of a structure based \
* on the process bitness. This can be used prior to reading any data \
* from a process. */ \
static size_t ExpectedSize(ProcessReader* process_reader); \
static size_t ExpectedSize(ProcessReader* process_reader);
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \
member_type member_name __VA_ARGS__;
@ -155,6 +164,7 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
using UIntPtr = typename Traits::UIntPtr; \
using Reserved32_64Only = typename Traits::Reserved32_64Only; \
using Reserved64_64Only = typename Traits::Reserved64_64Only; \
using Nothing = typename Traits::Nothing; \
\
/* Read(), ReadArrayInto(), and Size() are as in the generic user-visible \
* struct above. */ \

View File

@ -17,6 +17,8 @@
#include <string.h>
#include <sys/types.h>
#include <type_traits>
#include "base/logging.h"
#include "snapshot/mac/process_types/internal.h"
#include "util/mach/task_memory.h"
@ -62,46 +64,31 @@ bool ReadIntoVersioned(ProcessReader* process_reader,
template <typename Traits>
size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion(
decltype(dyld_all_image_infos<Traits>::version) version) {
if (version >= 14) {
return sizeof(dyld_all_image_infos<Traits>);
const size_t kSizeForVersion[] = {
offsetof(dyld_all_image_infos<Traits>, infoArrayCount), // 0
offsetof(dyld_all_image_infos<Traits>, libSystemInitialized), // 1
offsetof(dyld_all_image_infos<Traits>, jitInfo), // 2
offsetof(dyld_all_image_infos<Traits>, dyldVersion), // 3
offsetof(dyld_all_image_infos<Traits>, dyldVersion), // 4
offsetof(dyld_all_image_infos<Traits>, coreSymbolicationShmPage), // 5
offsetof(dyld_all_image_infos<Traits>, systemOrderFlag), // 6
offsetof(dyld_all_image_infos<Traits>, uuidArrayCount), // 7
offsetof(dyld_all_image_infos<Traits>, dyldAllImageInfosAddress), // 8
offsetof(dyld_all_image_infos<Traits>, initialImageCount), // 9
offsetof(dyld_all_image_infos<Traits>, errorKind), // 10
offsetof(dyld_all_image_infos<Traits>, sharedCacheSlide), // 11
offsetof(dyld_all_image_infos<Traits>, sharedCacheUUID), // 12
offsetof(dyld_all_image_infos<Traits>, infoArrayChangeTimestamp), // 13
offsetof(dyld_all_image_infos<Traits>, end), // 14
};
if (version >= arraysize(kSizeForVersion)) {
return kSizeForVersion[arraysize(kSizeForVersion) - 1];
}
if (version >= 13) {
return offsetof(dyld_all_image_infos<Traits>, infoArrayChangeTimestamp);
}
if (version >= 12) {
return offsetof(dyld_all_image_infos<Traits>, sharedCacheUUID);
}
if (version >= 11) {
return offsetof(dyld_all_image_infos<Traits>, sharedCacheSlide);
}
if (version >= 10) {
return offsetof(dyld_all_image_infos<Traits>, errorKind);
}
if (version >= 9) {
return offsetof(dyld_all_image_infos<Traits>, initialImageCount);
}
if (version >= 8) {
return offsetof(dyld_all_image_infos<Traits>, dyldAllImageInfosAddress);
}
if (version >= 7) {
return offsetof(dyld_all_image_infos<Traits>, uuidArrayCount);
}
if (version >= 6) {
return offsetof(dyld_all_image_infos<Traits>, systemOrderFlag);
}
if (version >= 5) {
return offsetof(dyld_all_image_infos<Traits>, coreSymbolicationShmPage);
}
if (version >= 3) {
return offsetof(dyld_all_image_infos<Traits>, dyldVersion);
}
if (version >= 2) {
return offsetof(dyld_all_image_infos<Traits>, jitInfo);
}
if (version >= 1) {
return offsetof(dyld_all_image_infos<Traits>, libSystemInitialized);
}
return offsetof(dyld_all_image_infos<Traits>, infoArrayCount);
static_assert(std::is_unsigned<decltype(version)>::value,
"version must be unsigned");
return kSizeForVersion[version];
}
// static

View File

@ -123,6 +123,13 @@ PROCESS_TYPE_STRUCT_BEGIN(dyld_all_image_infos)
PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_6)
PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_7)
PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_8)
// The 32-bit version of the structure will have four extra bytes of tail
// padding when built for 64-bit systems than it does natively and when built
// for 32-bit systems. Instead of using sizeof(dyld_all_image_infos), use
// offsetof(dyld_all_image_infos, end) to avoid taking this tail padding into
// account.
PROCESS_TYPE_STRUCT_MEMBER(Nothing, end)
PROCESS_TYPE_STRUCT_END(dyld_all_image_infos)
#endif // ! PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO &&

View File

@ -22,7 +22,8 @@
// DECLARE_PROCESS_TYPE_TRAITS_CLASS before #including this file again and after
// the last #include of this file.
//
// |Reserved*| are used for padding fields that may be zero-length, and thus
// |Reserved*| is used for padding fields that may be zero-length, and |Nothing|
// is always zero-length and is used solely as an anchor to compute offsets.
// __VA_ARGS__, which is intended to set the alignment of the 64-bit types, is
// not used for those type aliases.
#define DECLARE_PROCESS_TYPE_TRAITS_CLASS(traits_name, lp_bits, ...) \
@ -37,6 +38,7 @@
using UIntPtr = uint##lp_bits##_t __VA_ARGS__; \
using Reserved32_64Only = Reserved32_64Only##lp_bits; \
using Reserved64_64Only = Reserved64_64Only##lp_bits; \
using Nothing = Nothing; \
}; \
} \
} \

View File

@ -24,6 +24,7 @@
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "gtest/gtest.h"
#include "snapshot/mac/process_types/internal.h"
#include "test/mac/dyld.h"
#include "util/mac/mac_util.h"
#include "util/misc/implicit_cast.h"
@ -116,6 +117,42 @@ TEST(ProcessTypes, DyldImagesSelf) {
process_types::dyld_all_image_infos::ExpectedSizeForVersion(
&process_reader, kDyldAllImageInfosVersionInSDK));
// Make sure that the computed sizes of various versions of this structure are
// correct at different bitnessses.
const struct {
uint32_t version;
size_t size_32;
size_t size_64;
} kVersionsAndSizes[] = {
{1, 17, 25},
{2, 24, 40},
{3, 28, 48},
{5, 40, 72},
{6, 44, 80},
{7, 48, 88},
{8, 56, 104},
{9, 60, 112},
{10, 64, 120},
{11, 80, 152},
{12, 84, 160},
{13, 104, 184},
{14, 164, 304},
{15, 164, 304},
};
for (size_t index = 0; index < arraysize(kVersionsAndSizes); ++index) {
uint32_t version = kVersionsAndSizes[index].version;
SCOPED_TRACE(base::StringPrintf("index %zu, version %u", index, version));
EXPECT_EQ(kVersionsAndSizes[index].size_32,
process_types::internal::dyld_all_image_infos<
process_types::internal::Traits32>::
ExpectedSizeForVersion(version));
EXPECT_EQ(kVersionsAndSizes[index].size_64,
process_types::internal::dyld_all_image_infos<
process_types::internal::Traits64>::
ExpectedSizeForVersion(version));
}
process_types::dyld_all_image_infos proctype_image_infos;
ASSERT_TRUE(proctype_image_infos.Read(&process_reader,
dyld_info.all_image_info_addr));

View File

@ -19,6 +19,8 @@
#include <sys/utsname.h>
#include <time.h>
#include <algorithm>
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
@ -349,34 +351,44 @@ void SystemSnapshotMac::TimeZone(DaylightSavingTimeStatus* dst_status,
PCHECK(localtime_r(&snapshot_time_->tv_sec, &local)) << "localtime_r";
*standard_name = tzname[0];
bool found_transition = false;
long probe_gmtoff = local.tm_gmtoff;
if (daylight) {
// Scan forward and backward, one month at a time, looking for an instance
// when the observance of daylight saving time is different than it is in
// |local|.
long probe_gmtoff = local.tm_gmtoff;
// |local|. Its possible that no such instance will be found even with
// |daylight| set. This can happen in locations where daylight saving time
// was once observed or is expected to be observed in the future, but where
// no transitions to or from daylight saving time occurred or will occur
// within a year of the current date. Arizona, which last observed daylight
// saving time in 1967, is an example.
const int kMonthDeltas[] =
{ 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6,
7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12 };
for (size_t index = 0; index < arraysize(kMonthDeltas); ++index) {
// Look at the 15th day of each month at local noon. Set tm_isdst to -1 to
// avoid giving mktime() any hints about whether to consider daylight
// saving time in effect. mktime() accepts values of tm_mon that are
// outside of its normal range and behaves as expected: if tm_mon is -1,
// it references December of the preceding year, and if it is 12, it
for (size_t index = 0;
index < arraysize(kMonthDeltas) && !found_transition;
++index) {
// Look at a day of each month at local noon. Set tm_isdst to -1 to avoid
// giving mktime() any hints about whether to consider daylight saving
// time in effect. mktime() accepts values of tm_mon that are outside of
// its normal range and behaves as expected: if tm_mon is -1, it
// references December of the preceding year, and if it is 12, it
// references January of the following year.
tm probe_tm = {};
probe_tm.tm_hour = 12;
probe_tm.tm_mday = 15;
probe_tm.tm_mday = std::min(local.tm_mday, 28);
probe_tm.tm_mon = local.tm_mon + kMonthDeltas[index];
probe_tm.tm_year = local.tm_year;
probe_tm.tm_isdst = -1;
if (mktime(&probe_tm) != -1 && probe_tm.tm_isdst != local.tm_isdst) {
found_transition = true;
probe_gmtoff = probe_tm.tm_gmtoff;
break;
}
}
}
if (found_transition) {
*daylight_name = tzname[1];
if (!local.tm_isdst) {
*dst_status = kObservingStandardTime;

View File

@ -14,11 +14,13 @@
#include "snapshot/mac/system_snapshot_mac.h"
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <string>
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "gtest/gtest.h"
#include "snapshot/mac/process_reader.h"
@ -127,6 +129,39 @@ TEST_F(SystemSnapshotMacTest, MachineDescription) {
EXPECT_FALSE(system_snapshot().MachineDescription().empty());
}
class ScopedSetTZ {
public:
ScopedSetTZ(const std::string& tz) {
const char* old_tz = getenv(kTZ);
old_tz_set_ = old_tz;
if (old_tz_set_) {
old_tz_.assign(old_tz);
}
EXPECT_EQ(0, setenv(kTZ, tz.c_str(), 1)) << ErrnoMessage("setenv");
tzset();
}
~ScopedSetTZ() {
if (old_tz_set_) {
EXPECT_EQ(0, setenv(kTZ, old_tz_.c_str(), 1)) << ErrnoMessage("setenv");
} else {
EXPECT_EQ(0, unsetenv(kTZ)) << ErrnoMessage("unsetenv");
}
tzset();
}
private:
std::string old_tz_;
bool old_tz_set_;
static constexpr char kTZ[] = "TZ";
DISALLOW_COPY_AND_ASSIGN(ScopedSetTZ);
};
constexpr char ScopedSetTZ::kTZ[];
TEST_F(SystemSnapshotMacTest, TimeZone) {
SystemSnapshot::DaylightSavingTimeStatus dst_status;
int standard_offset_seconds;
@ -169,6 +204,68 @@ TEST_F(SystemSnapshotMacTest, TimeZone) {
EXPECT_NE(standard_name, daylight_name);
}
// Test a variety of time zones. Some of these observe daylight saving time,
// some dont. Some used to but no longer do. Some have uncommon UTC offsets.
const struct {
const char* tz;
bool observes_dst;
float standard_offset_hours;
float daylight_offset_hours;
const char* standard_name;
const char* daylight_name;
} kTestTimeZones[] = {
{"America/Anchorage", true, -9, -8, "AKST", "AKDT"},
{"America/Chicago", true, -6, -5, "CST", "CDT"},
{"America/Denver", true, -7, -6, "MST", "MDT"},
{"America/Halifax", true, -4, -3, "AST", "ADT"},
{"America/Los_Angeles", true, -8, -7, "PST", "PDT"},
{"America/New_York", true, -5, -4, "EST", "EDT"},
{"America/Phoenix", false, -7, -7, "MST", "MST"},
{"Asia/Karachi", false, 5, 5, "PKT", "PKT"},
{"Asia/Kolkata", false, 5.5, 5.5, "IST", "IST"},
{"Asia/Shanghai", false, 8, 8, "CST", "CST"},
{"Asia/Tokyo", false, 9, 9, "JST", "JST"},
{"Australia/Adelaide", true, 9.5, 10.5, "ACST", "ACDT"},
{"Australia/Brisbane", false, 10, 10, "AEST", "AEST"},
{"Australia/Darwin", false, 9.5, 9.5, "ACST", "ACST"},
{"Australia/Eucla", false, 8.75, 8.75, "ACWST", "ACWST"},
{"Australia/Lord_Howe", true, 10.5, 11, "LHST", "LHDT"},
{"Australia/Perth", false, 8, 8, "AWST", "AWST"},
{"Australia/Sydney", true, 10, 11, "AEST", "AEDT"},
{"Europe/Bucharest", true, 2, 3, "EET", "EEST"},
{"Europe/London", true, 0, 1, "GMT", "BST"},
{"Europe/Moscow", false, 3, 3, "MSK", "MSK"},
{"Europe/Paris", true, 1, 2, "CET", "CEST"},
{"Europe/Reykjavik", false, 0, 0, "UTC", "UTC"},
{"Pacific/Auckland", true, 12, 13, "NZST", "NZDT"},
{"Pacific/Honolulu", false, -10, -10, "HST", "HST"},
{"UTC", false, 0, 0, "UTC", "UTC"},
};
for (size_t index = 0; index < arraysize(kTestTimeZones); ++index) {
const auto& test_time_zone = kTestTimeZones[index];
const char* tz = test_time_zone.tz;
SCOPED_TRACE(base::StringPrintf("index %zu, tz %s", index, tz));
{
ScopedSetTZ set_tz(tz);
system_snapshot().TimeZone(&dst_status,
&standard_offset_seconds,
&daylight_offset_seconds,
&standard_name,
&daylight_name);
}
EXPECT_EQ(test_time_zone.observes_dst,
dst_status != SystemSnapshot::kDoesNotObserveDaylightSavingTime);
EXPECT_EQ(test_time_zone.standard_offset_hours * 60 * 60,
standard_offset_seconds);
EXPECT_EQ(test_time_zone.daylight_offset_hours * 60 * 60,
daylight_offset_seconds);
EXPECT_EQ(test_time_zone.standard_name, standard_name);
EXPECT_EQ(test_time_zone.daylight_name, daylight_name);
}
}
} // namespace

View File

@ -14,6 +14,7 @@
#include "snapshot/win/thread_snapshot_win.h"
#include <iterator>
#include <vector>
#include "base/logging.h"

View File

@ -20,6 +20,7 @@
#include <errno.h>
#include <libproc.h>
#include <kern/exc_resource.h>
#include <strings.h>
#include "base/logging.h"
#include "base/mac/mach_logging.h"
@ -200,16 +201,19 @@ int32_t ExceptionCodeForMetrics(exception_type_t exception,
// one another. For the purposes of encoding these codes for metrics,
// convert the flavor codes to their corresponding bit shift values.
const uint32_t guard_flavor = (code_0 >> 32) & 0x1fffffff;
uint8_t metrics_guard_flavor = 0xff;
for (int bit = 0; bit < 29; ++bit) {
const uint32_t test_mask = 1 << bit;
if (guard_flavor & test_mask) {
// Make sure that no other bits are set.
DCHECK_EQ(guard_flavor, test_mask);
const int first_bit = ffs(guard_flavor);
uint8_t metrics_guard_flavor;
if (first_bit) {
metrics_guard_flavor = first_bit - 1;
metrics_guard_flavor = bit;
break;
const uint32_t test_guard_flavor = 1 << metrics_guard_flavor;
if (guard_flavor != test_guard_flavor) {
// Another bit is set.
DCHECK_EQ(guard_flavor, test_guard_flavor);
metrics_guard_flavor = 0xff;
}
} else {
metrics_guard_flavor = 0xff;
}
metrics_code_0 = (guard_type << 8) | metrics_guard_flavor;
@ -305,15 +309,32 @@ bool IsExceptionNonfatalResource(exception_type_t exception,
if (resource_type == RESOURCE_TYPE_MEMORY &&
resource_flavor == FLAVOR_HIGH_WATERMARK) {
// These exceptions are never fatal. See 10.10
// These exceptions were never fatal prior to 10.12. See 10.10
// xnu-2782.1.97/osfmk/kern/task.c
// THIS_PROCESS_CROSSED_HIGH_WATERMARK__SENDING_EXC_RESOURCE().
//
// A superficial examination of 10.12 shows that these exceptions may be
// fatal, as determined by the P_MEMSTAT_FATAL_MEMLIMIT bit of the
// kernel-internal struct proc::p_memstat_state. See 10.12.3
// xnu-3789.41.3/osfmk/kern/task.c task_footprint_exceeded(). This bit is
// not exposed to user space, which makes it difficult to determine whether
// the kernel considers a given instance of this exception fatal. However, a
// close read reveals that it is only possible for this bit to become set
// when xnu-3789.41.3/bsd/kern/kern_memorystatus.c
// memorystatus_cmd_set_memlimit_properties() is called, which is only
// possible when the kernel is built with CONFIG_JETSAM set, or if the
// kern.memorystatus_highwater_enabled sysctl is used, which is only
// possible when the kernel is built with DEVELOPMENT or DEBUG set. Although
// CONFIG_JETSAM is used on iOS, it is not used on macOS. DEVELOPMENT and
// DEBUG are also not set for production kernels. It therefore remains
// impossible for these exceptions to be fatal, even on 10.12.
return true;
}
if (resource_type == RESOURCE_TYPE_IO) {
// These exceptions dont ever appear to be fatal. See
// https://crashpad.chromium.org/bug/124.
// These exceptions are never fatal. See 10.12.3
// xnu-3789.41.3/osfmk/kern/task.c
// SENDING_NOTIFICATION__THIS_PROCESS_IS_CAUSING_TOO_MUCH_IO().
return true;
}

View File

@ -57,7 +57,13 @@ TEST(ExceptionTypes, ExcCrashRecoverOriginalException) {
{0x0700080, EXC_SYSCALL, 128, 0},
{0x0706000, EXC_SYSCALL, 0x6000, 0},
{0x3000000, 0, 0, SIGQUIT},
{0x4000000, 0, 0, SIGILL},
{0x5000000, 0, 0, SIGTRAP},
{0x6000000, 0, 0, SIGABRT},
{0x7000000, 0, 0, SIGEMT},
{0x8000000, 0, 0, SIGFPE},
{0xa000000, 0, 0, SIGBUS},
{0xb000000, 0, 0, SIGSEGV},
{0xc000000, 0, 0, SIGSYS},
{0, 0, 0, 0},
};
@ -181,7 +187,13 @@ TEST(ExceptionTypes, ExceptionCodeForMetrics) {
#define ENCODE_EXC_CRASH_SIGNAL(signal) \
{ EXC_CRASH, (((signal) & 0xff) << 24), (EXC_CRASH << 16) | (signal) }
ENCODE_EXC_CRASH_SIGNAL(SIGQUIT),
ENCODE_EXC_CRASH_SIGNAL(SIGILL),
ENCODE_EXC_CRASH_SIGNAL(SIGTRAP),
ENCODE_EXC_CRASH_SIGNAL(SIGABRT),
ENCODE_EXC_CRASH_SIGNAL(SIGEMT),
ENCODE_EXC_CRASH_SIGNAL(SIGFPE),
ENCODE_EXC_CRASH_SIGNAL(SIGBUS),
ENCODE_EXC_CRASH_SIGNAL(SIGSEGV),
ENCODE_EXC_CRASH_SIGNAL(SIGSYS),
#undef ENCODE_EXC_CRASH_SIGNAL

View File

@ -20,7 +20,6 @@
#include <limits>
#include "base/logging.h"
#include "base/stl_util.h"
#include "util/misc/implicit_cast.h"
namespace crashpad {
@ -89,7 +88,8 @@ CompositeHTTPBodyStream::CompositeHTTPBodyStream(
}
CompositeHTTPBodyStream::~CompositeHTTPBodyStream() {
base::STLDeleteContainerPointers(parts_.begin(), parts_.end());
for (auto& item : parts_)
delete item;
}
FileOperationResult CompositeHTTPBodyStream::GetBytesBuffer(uint8_t* buffer,

View File

@ -26,7 +26,7 @@ process one HTTP request, deliver the prearranged response to the client, and
write the entire request to stdout. It will then terminate.
This server is written in Python since it provides a simple HTTP stack, and
because parsing Chunked encoding is safer and easier in a memory-safe language.
because parsing chunked encoding is safer and easier in a memory-safe language.
This could easily have been written in C++ instead.
"""
@ -80,7 +80,7 @@ class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
RequestHandler.raw_request = self.rfile.buffer
self.rfile.buffer = ''
if self.headers.get('Transfer-Encoding', '') == 'Chunked':
if self.headers.get('Transfer-Encoding', '').lower() == 'chunked':
body = self.handle_chunked_encoding()
else:
length = int(self.headers.get('Content-Length', -1))
@ -130,6 +130,10 @@ class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
return -1
return int(chunk_size_and_ext_line[:chunk_size_end], base=16)
def log_request(self, code='-', size='-'):
# The default implementation logs these to sys.stderr, which is just noise.
pass
def Main():
if sys.platform == 'win32':

View File

@ -15,17 +15,22 @@
#include "util/net/http_transport.h"
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <wchar.h>
#include <winhttp.h>
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/scoped_generic.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "package.h"
#include "util/file/file_io.h"
#include "util/numeric/safe_assignment.h"
#include "util/net/http_body.h"
namespace crashpad {
@ -34,7 +39,7 @@ namespace {
// PLOG doesn't work for messages from WinHTTP, so we need to use
// FORMAT_MESSAGE_FROM_HMODULE + the dll name manually here.
void LogErrorWinHttpMessage(const char* extra) {
std::string WinHttpMessage(const char* extra) {
DWORD error_code = GetLastError();
char msgbuf[256];
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
@ -46,15 +51,13 @@ void LogErrorWinHttpMessage(const char* extra) {
msgbuf,
arraysize(msgbuf),
NULL);
if (len) {
LOG(ERROR) << extra << ": " << msgbuf
<< base::StringPrintf(" (0x%X)", error_code);
} else {
LOG(ERROR) << base::StringPrintf(
"Error (0x%X) while retrieving error. (0x%X)",
GetLastError(),
error_code);
if (!len) {
return base::StringPrintf("%s: error 0x%x while retrieving error 0x%x",
extra,
GetLastError(),
error_code);
}
return base::StringPrintf("%s: %s (0x%x)", extra, msgbuf, error_code);
}
struct ScopedHINTERNETTraits {
@ -64,7 +67,7 @@ struct ScopedHINTERNETTraits {
static void Free(HINTERNET handle) {
if (handle) {
if (!WinHttpCloseHandle(handle)) {
LogErrorWinHttpMessage("WinHttpCloseHandle");
LOG(ERROR) << WinHttpMessage("WinHttpCloseHandle");
}
}
}
@ -97,7 +100,7 @@ bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
WINHTTP_NO_PROXY_BYPASS,
0));
if (!session.get()) {
LogErrorWinHttpMessage("WinHttpOpen");
LOG(ERROR) << WinHttpMessage("WinHttpOpen");
return false;
}
@ -107,7 +110,7 @@ bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
timeout_in_ms,
timeout_in_ms,
timeout_in_ms)) {
LogErrorWinHttpMessage("WinHttpSetTimeouts");
LOG(ERROR) << WinHttpMessage("WinHttpSetTimeouts");
return false;
}
@ -121,7 +124,7 @@ bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
// https://msdn.microsoft.com/en-us/library/aa384092.aspx
if (!WinHttpCrackUrl(
url_wide.c_str(), 0, 0, &url_components)) {
LogErrorWinHttpMessage("WinHttpCrackUrl");
LOG(ERROR) << WinHttpMessage("WinHttpCrackUrl");
return false;
}
DCHECK(url_components.nScheme == INTERNET_SCHEME_HTTP ||
@ -136,7 +139,7 @@ bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
ScopedHINTERNET connect(WinHttpConnect(
session.get(), host_name.c_str(), url_components.nPort, 0));
if (!connect.get()) {
LogErrorWinHttpMessage("WinHttpConnect");
LOG(ERROR) << WinHttpMessage("WinHttpConnect");
return false;
}
@ -150,57 +153,152 @@ bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
url_components.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE
: 0));
if (!request.get()) {
LogErrorWinHttpMessage("WinHttpOpenRequest");
LOG(ERROR) << WinHttpMessage("WinHttpOpenRequest");
return false;
}
// Add headers to the request.
//
// If Content-Length is not provided, implement chunked mode per RFC 7230
// §4.1.
//
// Note that chunked mode can only be used on Vista and later. Otherwise,
// WinHttpSendRequest() requires a real value for dwTotalLength, used for the
// Content-Length header. Determining that in the absence of a provided
// Content-Length would require reading the entire request body before calling
// WinHttpSendRequest().
bool chunked = true;
size_t content_length = 0;
for (const auto& pair : headers()) {
std::wstring header_string =
base::UTF8ToUTF16(pair.first) + L": " + base::UTF8ToUTF16(pair.second);
if (!WinHttpAddRequestHeaders(
request.get(),
header_string.c_str(),
base::checked_cast<DWORD>(header_string.size()),
WINHTTP_ADDREQ_FLAG_ADD)) {
LogErrorWinHttpMessage("WinHttpAddRequestHeaders");
return false;
if (pair.first == kContentLength) {
chunked = !base::StringToSizeT(pair.second, &content_length);
DCHECK(!chunked);
} else {
std::wstring header_string = base::UTF8ToUTF16(pair.first) + L": " +
base::UTF8ToUTF16(pair.second) + L"\r\n";
if (!WinHttpAddRequestHeaders(
request.get(),
header_string.c_str(),
base::checked_cast<DWORD>(header_string.size()),
WINHTTP_ADDREQ_FLAG_ADD)) {
LOG(ERROR) << WinHttpMessage("WinHttpAddRequestHeaders");
return false;
}
}
}
// We need the Content-Length up front, so buffer in memory. We should modify
// the interface to not require this, and then use WinHttpWriteData after
// WinHttpSendRequest.
std::vector<uint8_t> post_data;
// Write the body of a POST if any.
const size_t kBufferSize = 4096;
for (;;) {
uint8_t buffer[kBufferSize];
FileOperationResult bytes_to_write =
body_stream()->GetBytesBuffer(buffer, sizeof(buffer));
if (bytes_to_write == 0) {
break;
} else if (bytes_to_write < 0) {
LOG(ERROR) << "GetBytesBuffer failed";
DWORD content_length_dword;
if (chunked) {
const wchar_t kTransferEncodingHeader[] = L"Transfer-Encoding: chunked\r\n";
if (!WinHttpAddRequestHeaders(
request.get(),
kTransferEncodingHeader,
base::checked_cast<DWORD>(wcslen(kTransferEncodingHeader)),
WINHTTP_ADDREQ_FLAG_ADD)) {
LOG(ERROR) << WinHttpMessage("WinHttpAddRequestHeaders");
return false;
}
post_data.insert(post_data.end(), buffer, buffer + bytes_to_write);
content_length_dword = WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH;
} else if (!AssignIfInRange(&content_length_dword, content_length)) {
content_length_dword = WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH;
}
if (!WinHttpSendRequest(request.get(),
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
&post_data[0],
base::checked_cast<DWORD>(post_data.size()),
base::checked_cast<DWORD>(post_data.size()),
WINHTTP_NO_REQUEST_DATA,
0,
content_length_dword,
0)) {
LogErrorWinHttpMessage("WinHttpSendRequest");
LOG(ERROR) << WinHttpMessage("WinHttpSendRequest");
return false;
}
size_t total_written = 0;
FileOperationResult data_bytes;
do {
struct {
char size[8];
char crlf0[2];
uint8_t data[32 * 1024];
char crlf1[2];
} buf;
static_assert(sizeof(buf) == sizeof(buf.size) +
sizeof(buf.crlf0) +
sizeof(buf.data) +
sizeof(buf.crlf1),
"buf should not have padding");
// Read a block of data.
data_bytes = body_stream()->GetBytesBuffer(buf.data, sizeof(buf.data));
if (data_bytes == -1) {
return false;
}
DCHECK_GE(data_bytes, 0);
DCHECK_LE(static_cast<size_t>(data_bytes), sizeof(buf.data));
void* write_start;
DWORD write_size;
if (chunked) {
// Chunked encoding uses the entirety of buf. buf.size is presented in
// hexadecimal without any leading "0x". The terminating CR and LF will be
// placed immediately following the used portion of buf.data, even if
// buf.data is not full, and not necessarily in buf.crlf1.
unsigned int data_bytes_ui = base::checked_cast<unsigned int>(data_bytes);
// snprintf() would NUL-terminate, but _snprintf() wont.
int rv = _snprintf(buf.size, sizeof(buf.size), "%08x", data_bytes_ui);
DCHECK_GE(rv, 0);
DCHECK_EQ(static_cast<size_t>(rv), sizeof(buf.size));
DCHECK_NE(buf.size[sizeof(buf.size) - 1], '\0');
buf.crlf0[0] = '\r';
buf.crlf0[1] = '\n';
buf.data[data_bytes] = '\r';
buf.data[data_bytes + 1] = '\n';
// Skip leading zeroes in the chunk size.
unsigned int size_len;
for (size_len = sizeof(buf.size); size_len > 1; --size_len) {
if (buf.size[sizeof(buf.size) - size_len] != '0') {
break;
}
}
write_start = buf.crlf0 - size_len;
write_size = base::checked_cast<DWORD>(size_len + sizeof(buf.crlf0) +
data_bytes + sizeof(buf.crlf1));
} else {
// When not using chunked encoding, only use buf.data.
write_start = buf.data;
write_size = base::checked_cast<DWORD>(data_bytes);
}
// write_size will be 0 at EOF in non-chunked mode. Skip the write in that
// case. In contrast, at EOF in chunked mode, a zero-length chunk must be
// sent to signal EOF. This will happen when processing the EOF indicated by
// a 0 return from body_stream()->GetBytesBuffer() above.
if (write_size != 0) {
DWORD written;
if (!WinHttpWriteData(request.get(), write_start, write_size, &written)) {
LOG(ERROR) << WinHttpMessage("WinHttpWriteData");
return false;
}
DCHECK_EQ(written, write_size);
total_written += written;
}
} while (data_bytes > 0);
if (!chunked) {
DCHECK_EQ(total_written, content_length);
}
if (!WinHttpReceiveResponse(request.get(), nullptr)) {
LogErrorWinHttpMessage("WinHttpReceiveResponse");
LOG(ERROR) << WinHttpMessage("WinHttpReceiveResponse");
return false;
}
@ -214,7 +312,7 @@ bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
&status_code,
&sizeof_status_code,
WINHTTP_NO_HEADER_INDEX)) {
LogErrorWinHttpMessage("WinHttpQueryHeaders");
LOG(ERROR) << WinHttpMessage("WinHttpQueryHeaders");
return false;
}
@ -232,10 +330,10 @@ bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
// which executes synchronously, is only concerned with reading until EOF.
DWORD bytes_read = 0;
do {
char read_buffer[kBufferSize];
char read_buffer[4096];
if (!WinHttpReadData(
request.get(), read_buffer, sizeof(read_buffer), &bytes_read)) {
LogErrorWinHttpMessage("WinHttpReadData");
LOG(ERROR) << WinHttpMessage("WinHttpReadData");
return false;
}

View File

@ -18,30 +18,9 @@
#include <vector>
#include "base/macros.h"
#include "base/stl_util.h"
namespace crashpad {
//! \brief Allows a standard container to “own” pointer elements stored in it.
//!
//! When the container is destroyed, `delete` will be called on its pointer
//! elements.
//!
//! \note No attempt is made to `delete` elements that are removed from the
//! container by other means, such as replacement or `clear()`.
template <typename ContainerType>
class PointerContainer : public ContainerType {
public:
PointerContainer() : ContainerType(), pointer_deleter_(this) {}
~PointerContainer() {}
private:
base::STLElementDeleter<ContainerType> pointer_deleter_;
DISALLOW_COPY_AND_ASSIGN(PointerContainer);
};
//! \brief Allows a `std::vector` to “own” pointer elements stored in it.
//!
//! When the vector is destroyed, `delete` will be called on its pointer
@ -50,7 +29,18 @@ class PointerContainer : public ContainerType {
//! \note No attempt is made to `delete` elements that are removed from the
//! vector by other means, such as replacement or `clear()`.
template <typename T>
using PointerVector = PointerContainer<std::vector<T*>>;
class PointerVector : public std::vector<T*> {
public:
PointerVector() : std::vector<T*>() {}
~PointerVector() {
for (T* item : *this)
delete item;
}
private:
DISALLOW_COPY_AND_ASSIGN(PointerVector);
};
} // namespace crashpad

View File

@ -16,7 +16,6 @@
#include <sys/types.h>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/threading/thread_local_storage.h"
@ -28,14 +27,24 @@ namespace {
// handler. A thread may register its thread-specific log message list to
// receive messages produced just on that thread.
//
// Only one object of this class may exist in the program at a time. There must
// not be any log message handler in effect when it is created, and nothing else
// can be set as a log message handler while an object of this class exists.
//
// Practically, the only object of this class that might exist is managed by the
// g_master lazy instance, which will create it upon first use.
// Only one object of this class may exist in the program at a time as created
// by GetInstance(). There must not be any log message handler in effect when it
// is created, and nothing else can be set as a log message handler while an
// object of this class exists.
class ThreadLogMessagesMaster {
public:
void SetThreadMessageList(std::vector<std::string>* message_list) {
DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler);
DCHECK_NE(tls_.Get() != nullptr, message_list != nullptr);
tls_.Set(message_list);
}
static ThreadLogMessagesMaster* GetInstance() {
static auto master = new ThreadLogMessagesMaster();
return master;
}
private:
ThreadLogMessagesMaster() {
DCHECK(!tls_.initialized());
tls_.Initialize(nullptr);
@ -45,20 +54,8 @@ class ThreadLogMessagesMaster {
logging::SetLogMessageHandler(LogMessageHandler);
}
~ThreadLogMessagesMaster() {
DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler);
logging::SetLogMessageHandler(nullptr);
~ThreadLogMessagesMaster() = delete;
tls_.Free();
}
void SetThreadMessageList(std::vector<std::string>* message_list) {
DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler);
DCHECK_NE(tls_.Get() != nullptr, message_list != nullptr);
tls_.Set(message_list);
}
private:
static bool LogMessageHandler(logging::LogSeverity severity,
const char* file_path,
int line,
@ -84,18 +81,14 @@ class ThreadLogMessagesMaster {
base::ThreadLocalStorage::StaticSlot ThreadLogMessagesMaster::tls_
= TLS_INITIALIZER;
base::LazyInstance<ThreadLogMessagesMaster>::Leaky g_master =
LAZY_INSTANCE_INITIALIZER;
} // namespace
ThreadLogMessages::ThreadLogMessages()
: log_messages_() {
g_master.Get().SetThreadMessageList(&log_messages_);
ThreadLogMessages::ThreadLogMessages() : log_messages_() {
ThreadLogMessagesMaster::GetInstance()->SetThreadMessageList(&log_messages_);
}
ThreadLogMessages::~ThreadLogMessages() {
g_master.Get().SetThreadMessageList(nullptr);
ThreadLogMessagesMaster::GetInstance()->SetThreadMessageList(nullptr);
}
} // namespace crashpad

View File

@ -19,9 +19,12 @@
#include <algorithm>
#include <limits>
#include <memory>
#include <new>
#include <type_traits>
#include "base/logging.h"
#include "base/memory/free_deleter.h"
#include "base/process/memory.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "util/numeric/safe_assignment.h"
@ -36,6 +39,16 @@ namespace crashpad {
namespace {
using UniqueMallocPtr = std::unique_ptr<uint8_t[], base::FreeDeleter>;
UniqueMallocPtr UncheckedAllocate(size_t size) {
void* raw_ptr = nullptr;
if (!base::UncheckedMalloc(size, &raw_ptr))
return UniqueMallocPtr();
return UniqueMallocPtr(new (raw_ptr) uint8_t[size]);
}
NTSTATUS NtQueryInformationProcess(HANDLE process_handle,
PROCESSINFOCLASS process_information_class,
PVOID process_information,
@ -347,14 +360,20 @@ bool ReadMemoryInfo(HANDLE process, bool is_64_bit, ProcessInfo* process_info) {
std::vector<ProcessInfo::Handle> ProcessInfo::BuildHandleVector(
HANDLE process) const {
ULONG buffer_size = 2 * 1024 * 1024;
std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
// Typically if the buffer were too small, STATUS_INFO_LENGTH_MISMATCH would
// return the correct size in the final argument, but it does not for
// SystemExtendedHandleInformation, so we loop and attempt larger sizes.
NTSTATUS status;
ULONG returned_length;
UniqueMallocPtr buffer;
for (int tries = 0; tries < 5; ++tries) {
buffer.reset();
buffer = UncheckedAllocate(buffer_size);
if (!buffer) {
LOG(ERROR) << "UncheckedAllocate";
return std::vector<Handle>();
}
status = crashpad::NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(SystemExtendedHandleInformation),
buffer.get(),
@ -364,8 +383,6 @@ std::vector<ProcessInfo::Handle> ProcessInfo::BuildHandleVector(
break;
buffer_size *= 2;
buffer.reset();
buffer.reset(new uint8_t[buffer_size]);
}
if (!NT_SUCCESS(status)) {

View File

@ -170,6 +170,7 @@ class ProcessInfo {
bool is_64_bit,
ProcessInfo* process_info);
// This function is best-effort under low memory conditions.
std::vector<Handle> BuildHandleVector(HANDLE process) const;
pid_t process_id_;