Commit 6f117f26 authored by Robert Sesek's avatar Robert Sesek Committed by Commit Bot

Introduce the new CrashKeyString API.

This will replace the base/debug/crash_logging.h interface with an API
that is based off Crashpad's Annotations (https://crbug.com/crashpad/192).

Platforms that use Crashpad for crash reporting will indirectly use the
new Annotation API. Platforms still using Breakpad are provided a
source-compatible API that stores the data in the old NonAllocatingMap/
SimpleStringDictionary.

The InitializedArray template is courtesy of sdy@chromium.org.

Bug: 598854
Change-Id: Ic1b13ed9b3d504a1f90e119fa816d74fe3bdbff5
Reviewed-on: https://chromium-review.googlesource.com/757637Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Commit-Queue: Robert Sesek <rsesek@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517740}
parent 69f62439
...@@ -148,8 +148,6 @@ base::LazyInstance<MicrodumpInfo>::DestructorAtExit g_microdump_info = ...@@ -148,8 +148,6 @@ base::LazyInstance<MicrodumpInfo>::DestructorAtExit g_microdump_info =
#endif #endif
CrashKeyStorage* g_crash_keys = nullptr;
// Writes the value |v| as 16 hex characters to the memory pointed at by // Writes the value |v| as 16 hex characters to the memory pointed at by
// |output|. // |output|.
void write_uint64_hex(char* output, uint64_t v) { void write_uint64_hex(char* output, uint64_t v) {
...@@ -692,7 +690,7 @@ bool CrashDone(const MinidumpDescriptor& minidump, ...@@ -692,7 +690,7 @@ bool CrashDone(const MinidumpDescriptor& minidump,
info.process_start_time = g_process_start_time; info.process_start_time = g_process_start_time;
info.oom_size = base::g_oom_size; info.oom_size = base::g_oom_size;
info.pid = g_pid; info.pid = g_pid;
info.crash_keys = g_crash_keys; info.crash_keys = crash_reporter::internal::GetCrashKeyStorage();
HandleCrashDump(info); HandleCrashDump(info);
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
return !should_finalize || return !should_finalize ||
...@@ -871,7 +869,7 @@ bool CrashDoneInProcessNoUpload( ...@@ -871,7 +869,7 @@ bool CrashDoneInProcessNoUpload(
info.upload = false; info.upload = false;
info.process_start_time = g_process_start_time; info.process_start_time = g_process_start_time;
info.pid = g_pid; info.pid = g_pid;
info.crash_keys = g_crash_keys; info.crash_keys = crash_reporter::internal::GetCrashKeyStorage();
HandleCrashDump(info); HandleCrashDump(info);
return FinalizeCrashDoneAndroid(false /* is_browser_process */); return FinalizeCrashDoneAndroid(false /* is_browser_process */);
} }
...@@ -1033,7 +1031,7 @@ class NonBrowserCrashHandler : public google_breakpad::CrashGenerationClient { ...@@ -1033,7 +1031,7 @@ class NonBrowserCrashHandler : public google_breakpad::CrashGenerationClient {
iov[4].iov_base = &base::g_oom_size; iov[4].iov_base = &base::g_oom_size;
iov[4].iov_len = sizeof(base::g_oom_size); iov[4].iov_len = sizeof(base::g_oom_size);
google_breakpad::SerializedNonAllocatingMap* serialized_map; google_breakpad::SerializedNonAllocatingMap* serialized_map;
iov[5].iov_len = g_crash_keys->Serialize( iov[5].iov_len = crash_reporter::internal::GetCrashKeyStorage()->Serialize(
const_cast<const google_breakpad::SerializedNonAllocatingMap**>( const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
&serialized_map)); &serialized_map));
iov[5].iov_base = serialized_map; iov[5].iov_base = serialized_map;
...@@ -1112,18 +1110,19 @@ bool IsInWhiteList(const base::StringPiece& key) { ...@@ -1112,18 +1110,19 @@ bool IsInWhiteList(const base::StringPiece& key) {
void SetCrashKeyValue(const base::StringPiece& key, void SetCrashKeyValue(const base::StringPiece& key,
const base::StringPiece& value) { const base::StringPiece& value) {
if (!g_use_crash_key_white_list || IsInWhiteList(key)) { if (!g_use_crash_key_white_list || IsInWhiteList(key)) {
g_crash_keys->SetKeyValue(key.data(), value.data()); crash_reporter::internal::GetCrashKeyStorage()->SetKeyValue(key.data(),
value.data());
} }
} }
void ClearCrashKey(const base::StringPiece& key) { void ClearCrashKey(const base::StringPiece& key) {
g_crash_keys->RemoveKey(key.data()); crash_reporter::internal::GetCrashKeyStorage()->RemoveKey(key.data());
} }
// GetCrashReporterClient() cannot call any Set methods until after // GetCrashReporterClient() cannot call any Set methods until after
// InitCrashKeys(). // InitCrashKeys().
void InitCrashKeys() { void InitCrashKeys() {
g_crash_keys = new CrashKeyStorage; crash_reporter::InitializeCrashKeys();
GetCrashReporterClient()->RegisterCrashKeys(); GetCrashReporterClient()->RegisterCrashKeys();
g_use_crash_key_white_list = g_use_crash_key_white_list =
GetCrashReporterClient()->UseCrashKeysWhiteList(); GetCrashReporterClient()->UseCrashKeysWhiteList();
...@@ -1800,9 +1799,13 @@ void HandleCrashDump(const BreakpadInfo& info) { ...@@ -1800,9 +1799,13 @@ void HandleCrashDump(const BreakpadInfo& info) {
} }
if (info.crash_keys) { if (info.crash_keys) {
using CrashKeyStorage =
crash_reporter::internal::TransitionalCrashKeyStorage;
CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys); CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys);
const CrashKeyStorage::Entry* entry; const CrashKeyStorage::Entry* entry;
while ((entry = crash_key_iterator.Next())) { while ((entry = crash_key_iterator.Next())) {
if (g_use_crash_key_white_list && !IsInWhiteList(entry->key))
continue;
writer.AddPairString(entry->key, entry->value); writer.AddPairString(entry->key, entry->value);
writer.AddBoundary(); writer.AddBoundary();
writer.Flush(); writer.Flush();
......
...@@ -13,12 +13,10 @@ ...@@ -13,12 +13,10 @@
#include <sys/types.h> #include <sys/types.h>
#include "components/crash/content/app/breakpad_linux.h" #include "components/crash/content/app/breakpad_linux.h"
#include "third_party/breakpad/breakpad/src/common/simple_string_dictionary.h" #include "components/crash/core/common/crash_key_internal.h"
namespace breakpad { namespace breakpad {
typedef google_breakpad::NonAllocatingMap<256, 256, 64> CrashKeyStorage;
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
static const size_t kMaxAsanReportSize = 1 << 16; static const size_t kMaxAsanReportSize = 1 << 16;
#endif #endif
...@@ -55,7 +53,7 @@ struct BreakpadInfo { ...@@ -55,7 +53,7 @@ struct BreakpadInfo {
uint64_t process_start_time; // Uptime of the crashing process. uint64_t process_start_time; // Uptime of the crashing process.
size_t oom_size; // Amount of memory requested if OOM. size_t oom_size; // Amount of memory requested if OOM.
uint64_t pid; // PID where applicable. uint64_t pid; // PID where applicable.
CrashKeyStorage* crash_keys; crash_reporter::internal::TransitionalCrashKeyStorage* crash_keys;
}; };
extern void HandleCrashDump(const BreakpadInfo& info); extern void HandleCrashDump(const BreakpadInfo& info);
......
...@@ -170,7 +170,8 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { ...@@ -170,7 +170,8 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
auto asan_report = base::MakeUnique<char[]>(kMaxAsanReportSize + 1); auto asan_report = base::MakeUnique<char[]>(kMaxAsanReportSize + 1);
#endif #endif
auto crash_keys = base::MakeUnique<CrashKeyStorage>(); auto crash_keys =
base::MakeUnique<crash_reporter::internal::TransitionalCrashKeyStorage>();
google_breakpad::SerializedNonAllocatingMap* serialized_crash_keys; google_breakpad::SerializedNonAllocatingMap* serialized_crash_keys;
size_t crash_keys_size = crash_keys->Serialize( size_t crash_keys_size = crash_keys->Serialize(
const_cast<const google_breakpad::SerializedNonAllocatingMap**>( const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
...@@ -311,7 +312,8 @@ void CrashHandlerHostLinux::FindCrashingThreadAndDump( ...@@ -311,7 +312,8 @@ void CrashHandlerHostLinux::FindCrashingThreadAndDump(
pid_t crashing_pid, pid_t crashing_pid,
const std::string& expected_syscall_data, const std::string& expected_syscall_data,
std::unique_ptr<char[]> crash_context, std::unique_ptr<char[]> crash_context,
std::unique_ptr<CrashKeyStorage> crash_keys, std::unique_ptr<crash_reporter::internal::TransitionalCrashKeyStorage>
crash_keys,
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
std::unique_ptr<char[]> asan_report, std::unique_ptr<char[]> asan_report,
#endif #endif
......
...@@ -72,17 +72,19 @@ class CrashHandlerHostLinux : public base::MessageLoopForIO::Watcher, ...@@ -72,17 +72,19 @@ class CrashHandlerHostLinux : public base::MessageLoopForIO::Watcher,
void QueueCrashDumpTask(std::unique_ptr<BreakpadInfo> info, int signal_fd); void QueueCrashDumpTask(std::unique_ptr<BreakpadInfo> info, int signal_fd);
// Find crashing thread (may delay and retry) and dump on IPC thread. // Find crashing thread (may delay and retry) and dump on IPC thread.
void FindCrashingThreadAndDump(pid_t crashing_pid, void FindCrashingThreadAndDump(
const std::string& expected_syscall_data, pid_t crashing_pid,
std::unique_ptr<char[]> crash_context, const std::string& expected_syscall_data,
std::unique_ptr<CrashKeyStorage> crash_keys, std::unique_ptr<char[]> crash_context,
std::unique_ptr<crash_reporter::internal::TransitionalCrashKeyStorage>
crash_keys,
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
std::unique_ptr<char[]> asan_report, std::unique_ptr<char[]> asan_report,
#endif #endif
uint64_t uptime, uint64_t uptime,
size_t oom_size, size_t oom_size,
int signal_fd, int signal_fd,
int attempt); int attempt);
const std::string process_type_; const std::string process_type_;
const base::FilePath dumps_path_; const base::FilePath dumps_path_;
......
...@@ -3,5 +3,8 @@ ...@@ -3,5 +3,8 @@
include_rules = [ include_rules = [
"-components", "-components",
"+components/crash/core", "+components/crash/core",
"+third_party/crashpad/crashpad/client/annotation.h",
"+third_party/crashpad/crashpad/client/annotation_list.h",
"+third_party/breakpad/breakpad/src/common/simple_string_dictionary.h",
"-net", "-net",
] ]
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
group("common") { group("common") {
public_deps = [ public_deps = [
":crash_keys", ":crash_key",
":crash_key_utils",
] ]
if (is_mac || is_ios) { if (is_mac || is_ios) {
...@@ -12,7 +13,33 @@ group("common") { ...@@ -12,7 +13,33 @@ group("common") {
} }
} }
static_library("crash_keys") { static_library("crash_key") {
sources = [
"crash_key.h",
]
deps = [
"//base",
]
if (is_mac || is_win) {
sources += [ "crash_key_crashpad.cc" ]
deps += [ "//third_party/crashpad/crashpad/client" ]
} else if (is_fuchsia) {
sources += [ "crash_key_stubs.cc" ]
} else {
include_dirs = [ "//third_party/breakpad/breakpad/src/" ]
sources += [
"crash_key_breakpad.cc",
"crash_key_internal.h",
]
deps += [ "//third_party/breakpad:client" ]
}
}
static_library("crash_key_utils") {
visibility = [ ":*" ] visibility = [ ":*" ]
sources = [ sources = [
...@@ -21,6 +48,7 @@ static_library("crash_keys") { ...@@ -21,6 +48,7 @@ static_library("crash_keys") {
] ]
deps = [ deps = [
":crash_key",
"//base", "//base",
] ]
} }
...@@ -38,7 +66,7 @@ if (is_mac || is_ios) { ...@@ -38,7 +66,7 @@ if (is_mac || is_ios) {
defines = [ "CRASH_CORE_COMMON_IMPLEMENTATION" ] defines = [ "CRASH_CORE_COMMON_IMPLEMENTATION" ]
deps = [ deps = [
":crash_keys", ":crash_key_utils",
"//base", "//base",
] ]
...@@ -49,6 +77,7 @@ if (is_mac || is_ios) { ...@@ -49,6 +77,7 @@ if (is_mac || is_ios) {
source_set("unit_tests") { source_set("unit_tests") {
testonly = true testonly = true
sources = [ sources = [
"crash_key_unittest.cc",
"crash_keys_unittest.cc", "crash_keys_unittest.cc",
] ]
...@@ -61,4 +90,13 @@ source_set("unit_tests") { ...@@ -61,4 +90,13 @@ source_set("unit_tests") {
if (is_mac || is_ios) { if (is_mac || is_ios) {
sources += [ "objc_zombie_unittest.mm" ] sources += [ "objc_zombie_unittest.mm" ]
} }
if (!is_mac && !is_win && !is_fuchsia) {
include_dirs = [ "//third_party/breakpad/breakpad/src/" ]
sources += [ "crash_key_breakpad_unittest.cc" ]
}
if (is_fuchsia) {
sources -= [ "crash_key_unittest.cc" ]
}
} }
// Copyright 2017 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 COMPONENTS_CRASH_CORE_COMMON_CRASH_KEY_H_
#define COMPONENTS_CRASH_CORE_COMMON_CRASH_KEY_H_
#include <stdint.h>
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
// The crash key interface exposed by this file is the same as the Crashpad
// Annotation interface. Because not all platforms use Crashpad yet, a
// source-compatible interface is provided on top of the older Breakpad
// storage mechanism.
#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
#define USE_CRASHPAD_ANNOTATION 1
#endif
#if defined(USE_CRASHPAD_ANNOTATION)
#include "third_party/crashpad/crashpad/client/annotation.h"
#endif
namespace crash_reporter {
class CrashKeyBreakpadTest;
// A CrashKeyString stores a name-value pair that will be recorded within a
// crash report.
//
// The crash key name must be a constant string expression, and the value
// should be unique and identifying. The maximum size for the value is
// specified as the template argument, and values greater than this are
// truncated. Crash keys should be declared with static storage duration.
//
// Example:
// namespace {
// crash_reporter::CrashKeyString<256> g_active_url("current-page-url");
// }
//
// void DidNaviagate(GURL new_url) {
// g_active_url.Set(new_url.ToString());
// }
#if defined(USE_CRASHPAD_ANNOTATION)
template <crashpad::Annotation::ValueSizeType MaxLength>
using CrashKeyString = crashpad::StringAnnotation<MaxLength>;
#else // Crashpad-compatible crash key interface:
namespace internal {
constexpr size_t kCrashKeyStorageNumEntries = 200;
constexpr size_t kCrashKeyStorageValueSize = 128;
// Base implementation of a CrashKeyString for non-Crashpad clients. A separate
// base class is used to avoid inlining complex logic into the public template
// API.
class CrashKeyStringImpl {
public:
constexpr explicit CrashKeyStringImpl(const char name[],
size_t* index_array,
size_t index_array_count)
: name_(name),
index_array_(index_array),
index_array_count_(index_array_count) {}
void Set(base::StringPiece value);
void Clear();
bool is_set() const;
private:
friend class crash_reporter::CrashKeyBreakpadTest;
// The name of the crash key.
const char* const name_;
// If the crash key is set, this is the index into the storage that can be
// used to set/clear the key without requiring a linear scan of the storage
// table. This will be |num_entries| if unset.
size_t* index_array_;
size_t index_array_count_;
DISALLOW_COPY_AND_ASSIGN(CrashKeyStringImpl);
};
// This type creates a C array that is initialized with a specific default
// value, rather than the standard zero-initialized default.
template <typename T,
size_t TotalSize,
T DefaultValue,
size_t Count,
T... Values>
struct InitializedArrayImpl {
using Type = typename InitializedArrayImpl<T,
TotalSize,
DefaultValue,
Count - 1,
DefaultValue,
Values...>::Type;
};
template <typename T, size_t TotalSize, T DefaultValue, T... Values>
struct InitializedArrayImpl<T, TotalSize, DefaultValue, 0, Values...> {
using Type = InitializedArrayImpl<T, TotalSize, DefaultValue, 0, Values...>;
T data[TotalSize]{Values...};
};
template <typename T, size_t ArraySize, T DefaultValue>
using InitializedArray =
typename InitializedArrayImpl<T, ArraySize, DefaultValue, ArraySize>::Type;
} // namespace internal
template <uint32_t MaxLength>
class CrashKeyString : public internal::CrashKeyStringImpl {
public:
constexpr static size_t chunk_count =
(MaxLength / internal::kCrashKeyStorageValueSize) + 1;
constexpr explicit CrashKeyString(const char name[])
: internal::CrashKeyStringImpl(name, indexes_.data, chunk_count) {}
private:
// Indexes into the TransitionalCrashKeyStorage for when a value is set.
// See the comment in CrashKeyStringImpl for details.
// An unset index in the storage is represented by a sentinel value, which
// is the total number of entries. This will initialize the array with
// that sentinel value as a compile-time expression.
internal::InitializedArray<size_t,
chunk_count,
internal::kCrashKeyStorageNumEntries>
indexes_;
DISALLOW_COPY_AND_ASSIGN(CrashKeyString);
};
#endif
// This scoper clears the specified annotation's value when it goes out of
// scope.
//
// Example:
// void DoSomething(const std::string& data) {
// static crash_reporter::CrashKeyString<32> crash_key("DoSomething-data");
// crash_reporter::ScopedCrashKeyString auto_clear(&crash_key, data);
//
// DoSomethignImpl(data);
// }
class ScopedCrashKeyString {
public:
#if defined(USE_CRASHPAD_ANNOTATION)
using CrashKeyType = crashpad::Annotation;
#else
using CrashKeyType = internal::CrashKeyStringImpl;
#endif
template <class T>
ScopedCrashKeyString(T* crash_key, base::StringPiece value)
: crash_key_(crash_key) {
crash_key->Set(value);
}
~ScopedCrashKeyString() { crash_key_->Clear(); }
private:
CrashKeyType* const crash_key_;
DISALLOW_COPY_AND_ASSIGN(ScopedCrashKeyString);
};
// Initializes the crash key subsystem if it is required.
void InitializeCrashKeys();
} // namespace crash_reporter
#undef USE_CRASHPAD_ANNOTATION
#endif // COMPONENTS_CRASH_CORE_COMMON_CRASH_KEY_H_
// Copyright 2017 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.
// NOTE: This file is only compiled when Crashpad is not used as the crash
// reproter.
#include "components/crash/core/common/crash_key.h"
#include "base/format_macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "components/crash/core/common/crash_key_internal.h"
#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
#error "This file should not be used when Crashpad is available."
#endif
namespace crash_reporter {
namespace internal {
namespace {
// String used to format chunked key names.
const char kChunkFormatString[] = "%s-%" PRIuS;
static TransitionalCrashKeyStorage* g_storage = nullptr;
} // namespace
TransitionalCrashKeyStorage* GetCrashKeyStorage() {
return g_storage;
}
void ResetCrashKeyStorageForTesting() {
auto* storage = g_storage;
g_storage = nullptr;
delete storage;
}
void CrashKeyStringImpl::Set(base::StringPiece value) {
const size_t kValueMaxLength = index_array_count_ * kCrashKeyStorageValueSize;
TransitionalCrashKeyStorage* storage = GetCrashKeyStorage();
value = value.substr(0, kValueMaxLength);
// If there is only one slot for the value, then handle it directly.
if (index_array_count_ == 1) {
std::string value_string = value.as_string();
if (is_set()) {
storage->SetValueAtIndex(index_array_[0], value_string.c_str());
} else {
index_array_[0] = storage->SetKeyValue(name_, value_string.c_str());
}
return;
}
// Otherwise, break the value into chunks labeled name-1 through name-N,
// where N is |index_array_count_|.
size_t offset = 0;
for (size_t i = 0; i < index_array_count_; ++i) {
if (offset < value.length()) {
// The storage NUL-terminates the value, so ensure that a byte is
// not lost when setting individaul chunks.
base::StringPiece chunk =
value.substr(offset, kCrashKeyStorageValueSize - 1);
offset += chunk.length();
if (index_array_[i] == TransitionalCrashKeyStorage::num_entries) {
std::string chunk_name =
base::StringPrintf(kChunkFormatString, name_, i + 1);
index_array_[i] =
storage->SetKeyValue(chunk_name.c_str(), chunk.data());
} else {
storage->SetValueAtIndex(index_array_[i], chunk.data());
}
} else {
storage->RemoveAtIndex(index_array_[i]);
index_array_[i] = TransitionalCrashKeyStorage::num_entries;
}
}
}
void CrashKeyStringImpl::Clear() {
for (size_t i = 0; i < index_array_count_; ++i) {
GetCrashKeyStorage()->RemoveAtIndex(index_array_[i]);
index_array_[i] = TransitionalCrashKeyStorage::num_entries;
}
}
bool CrashKeyStringImpl::is_set() const {
return index_array_[0] != TransitionalCrashKeyStorage::num_entries;
}
} // namespace internal
void InitializeCrashKeys() {
if (!internal::g_storage) {
internal::g_storage = new internal::TransitionalCrashKeyStorage();
}
}
} // namespace crash_reporter
// Copyright 2017 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 "components/crash/core/common/crash_key.h"
#include "components/crash/core/common/crash_key_internal.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace crash_reporter {
class CrashKeyBreakpadTest : public testing::Test {
public:
void SetUp() override {
InitializeCrashKeys();
ASSERT_TRUE(internal::GetCrashKeyStorage());
}
void TearDown() override { internal::ResetCrashKeyStorageForTesting(); }
internal::TransitionalCrashKeyStorage* storage() {
return internal::GetCrashKeyStorage();
}
size_t* GetIndexArray(internal::CrashKeyStringImpl* key) {
return key->index_array_;
}
size_t GetIndexArrayCount(internal::CrashKeyStringImpl* key) {
return key->index_array_count_;
}
};
TEST_F(CrashKeyBreakpadTest, ConstantAssertions) {
// Tests in this file generate and validate data based on constants
// having specific values. This test asserts those assumptions.
EXPECT_EQ(128u, internal::kCrashKeyStorageValueSize);
}
TEST_F(CrashKeyBreakpadTest, Allocation) {
const size_t kSentinel = internal::kCrashKeyStorageNumEntries;
static CrashKeyString<32> key1("short");
ASSERT_EQ(1u, GetIndexArrayCount(&key1));
auto* indexes = GetIndexArray(&key1);
EXPECT_EQ(kSentinel, indexes[0]);
// An extra index slot is created for lengths equal to the value size.
static CrashKeyString<128> key2("extra");
ASSERT_EQ(2u, GetIndexArrayCount(&key2));
indexes = GetIndexArray(&key2);
EXPECT_EQ(kSentinel, indexes[0]);
EXPECT_EQ(kSentinel, indexes[1]);
static CrashKeyString<395> key3("large");
ASSERT_EQ(4u, GetIndexArrayCount(&key3));
indexes = GetIndexArray(&key3);
EXPECT_EQ(kSentinel, indexes[0]);
EXPECT_EQ(kSentinel, indexes[1]);
EXPECT_EQ(kSentinel, indexes[2]);
EXPECT_EQ(kSentinel, indexes[3]);
}
TEST_F(CrashKeyBreakpadTest, SetClearSingle) {
static CrashKeyString<32> key("test-key");
EXPECT_FALSE(storage()->GetValueForKey("test-key"));
EXPECT_EQ(0u, storage()->GetCount());
key.Set("value");
ASSERT_EQ(1u, storage()->GetCount());
EXPECT_STREQ("value", storage()->GetValueForKey("test-key"));
key.Set("value 2");
ASSERT_EQ(1u, storage()->GetCount());
EXPECT_STREQ("value 2", storage()->GetValueForKey("test-key"));
key.Clear();
EXPECT_FALSE(storage()->GetValueForKey("test-key"));
EXPECT_EQ(0u, storage()->GetCount());
}
TEST_F(CrashKeyBreakpadTest, SetChunked) {
std::string chunk1(128, 'A');
std::string chunk2(128, 'B');
std::string chunk3(128, 'C');
static CrashKeyString<400> key("chunky");
EXPECT_EQ(0u, storage()->GetCount());
key.Set((chunk1 + chunk2 + chunk3).c_str());
ASSERT_EQ(4u, storage()->GetCount());
// Since chunk1 through chunk3 are the same size as a storage slot,
// and the storage NUL-terminates the value, ensure no bytes are
// lost when chunking.
EXPECT_EQ(std::string(127, 'A'), storage()->GetValueForKey("chunky-1"));
EXPECT_EQ(std::string("A") + std::string(126, 'B'),
storage()->GetValueForKey("chunky-2"));
EXPECT_EQ(std::string(2, 'B') + std::string(125, 'C'),
storage()->GetValueForKey("chunky-3"));
EXPECT_EQ(std::string(3, 'C'), storage()->GetValueForKey("chunky-4"));
std::string chunk4(240, 'D');
key.Set(chunk4.c_str());
ASSERT_EQ(2u, storage()->GetCount());
EXPECT_EQ(std::string(127, 'D'), storage()->GetValueForKey("chunky-1"));
EXPECT_EQ(std::string(240 - 127, 'D'), storage()->GetValueForKey("chunky-2"));
EXPECT_FALSE(storage()->GetValueForKey("chunky-3"));
key.Clear();
EXPECT_EQ(0u, storage()->GetCount());
}
TEST_F(CrashKeyBreakpadTest, SetTwoChunked) {
static CrashKeyString<600> key1("big");
static CrashKeyString<256> key2("small");
EXPECT_EQ(0u, storage()->GetCount());
key1.Set(std::string(200, '1').c_str());
ASSERT_EQ(2u, storage()->GetCount());
EXPECT_EQ(std::string(127, '1'), storage()->GetValueForKey("big-1"));
EXPECT_EQ(std::string(73, '1'), storage()->GetValueForKey("big-2"));
key2.Set(std::string(256, '2').c_str());
ASSERT_EQ(5u, storage()->GetCount());
EXPECT_EQ(std::string(127, '1'), storage()->GetValueForKey("big-1"));
EXPECT_EQ(std::string(73, '1'), storage()->GetValueForKey("big-2"));
EXPECT_EQ(std::string(127, '2'), storage()->GetValueForKey("small-1"));
EXPECT_EQ(std::string(127, '2'), storage()->GetValueForKey("small-2"));
EXPECT_EQ(std::string(2, '2'), storage()->GetValueForKey("small-3"));
key1.Set(std::string(510, '3').c_str());
ASSERT_EQ(8u, storage()->GetCount());
EXPECT_EQ(std::string(127, '3'), storage()->GetValueForKey("big-1"));
EXPECT_EQ(std::string(127, '3'), storage()->GetValueForKey("big-2"));
EXPECT_EQ(std::string(127, '3'), storage()->GetValueForKey("big-3"));
EXPECT_EQ(std::string(127, '3'), storage()->GetValueForKey("big-4"));
EXPECT_EQ(std::string(2, '3'), storage()->GetValueForKey("big-5"));
EXPECT_EQ(std::string(127, '2'), storage()->GetValueForKey("small-1"));
EXPECT_EQ(std::string(127, '2'), storage()->GetValueForKey("small-2"));
EXPECT_EQ(std::string(2, '2'), storage()->GetValueForKey("small-3"));
key2.Clear();
ASSERT_EQ(5u, storage()->GetCount());
EXPECT_EQ(std::string(127, '3'), storage()->GetValueForKey("big-1"));
EXPECT_EQ(std::string(127, '3'), storage()->GetValueForKey("big-2"));
EXPECT_EQ(std::string(127, '3'), storage()->GetValueForKey("big-3"));
EXPECT_EQ(std::string(127, '3'), storage()->GetValueForKey("big-4"));
EXPECT_EQ(std::string(2, '3'), storage()->GetValueForKey("big-5"));
}
} // namespace crash_reporter
// Copyright 2017 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.
// NOTE: This file is only compiled when Crashpad is used as the crash
// reproter.
#include "components/crash/core/common/crash_key.h"
#include "third_party/crashpad/crashpad/client/annotation_list.h"
namespace crash_reporter {
void InitializeCrashKeys() {
crashpad::AnnotationList::Register();
}
} // namespace crash_reporter
// Copyright 2017 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 COMPONENTS_CRASH_CORE_COMMON_CRASH_KEY_INTERNAL_H_
#define COMPONENTS_CRASH_CORE_COMMON_CRASH_KEY_INTERNAL_H_
#include "components/crash/core/common/crash_key.h"
#include "third_party/breakpad/breakpad/src/common/simple_string_dictionary.h"
namespace crash_reporter {
namespace internal {
using TransitionalCrashKeyStorage = google_breakpad::
NonAllocatingMap<40, kCrashKeyStorageValueSize, kCrashKeyStorageNumEntries>;
// Accesses the underlying storage for crash keys for non-Crashpad clients.
TransitionalCrashKeyStorage* GetCrashKeyStorage();
void ResetCrashKeyStorageForTesting();
} // namespace internal
} // namespace crash_reporter
#endif // COMPONENTS_CRASH_CORE_COMMON_CRASH_KEY_INTERNAL_H_
// Copyright 2017 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.
// This file is only used for OS_FUCHSIA, since there is no crash reporter
// for that platform.
#include "build/build_config.h"
#include "components/crash/core/common/crash_key.h"
#if !defined(OS_FUCHSIA)
#error "This file is only for OS_FUCHSIA."
#endif
namespace crash_reporter {
namespace internal {
void CrashKeyStringImpl::Set(base::StringPiece value) {}
void CrashKeyStringImpl::Clear() {}
bool CrashKeyStringImpl::is_set() const {
return false;
}
} // namespace internal
void InitializeCrashKeys() {}
} // namespace crash_reporter
// Copyright 2017 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 "components/crash/core/common/crash_key.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace crash_reporter {
namespace {
class CrashKeyStringTest : public testing::Test {
public:
void SetUp() override { InitializeCrashKeys(); }
};
TEST_F(CrashKeyStringTest, ScopedCrashKeyString) {
static CrashKeyString<32> key("test-scope");
EXPECT_FALSE(key.is_set());
{
ScopedCrashKeyString scoper(&key, "value");
EXPECT_TRUE(key.is_set());
}
EXPECT_FALSE(key.is_set());
}
} // namespace
} // namespace crash_reporter
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