File: crash_key.h

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,122,156 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (261 lines) | stat: -rw-r--r-- 9,339 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
// Copyright 2017 The Chromium Authors
// 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 <string>
#include <string_view>

#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "build/build_config.h"
#include "components/crash/core/common/crash_buildflags.h"
#include "components/crash/core/common/crash_export.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.
//
// See https://cs.chromium.org/chromium/src/docs/debugging_with_crash_keys.md
// for more information on using this.
#if BUILDFLAG(USE_CRASHPAD_ANNOTATION)
#include "third_party/crashpad/crashpad/client/annotation.h"  // nogncheck
#endif

namespace base {
namespace debug {
class StackTrace;
}  // namespace debug
}  // namespace base

namespace crash_reporter {

// 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. When specifying a value size, space should be left for the
// `NUL` byte. Crash keys should be declared with static storage duration.
//
// Examples:
// \code
//    // This crash key is only set in one function:
//    void DidNavigate(const GURL& gurl) {
//      static crash_reporter::CrashKeyString<256> url_key("url");
//      url_key.Set(gurl.ToString());
//    }
//
//    // This crash key can be set/cleared across different functions:
//    namespace {
//    crash_reporter::CrashKeyString<32> g_operation_id("operation-req-id");
//    }
//
//    void OnStartingOperation(const std::string& request_id) {
//      g_operation_id.Set(request_id);
//    }
//
//    void OnEndingOperation() {
//      g_operation_id.Clear()
//    }
// \endcode
#if BUILDFLAG(USE_CRASHPAD_ANNOTATION)

template <crashpad::Annotation::ValueSizeType MaxLength>
using CrashKeyString = crashpad::StringAnnotation<MaxLength>;

#else  // Crashpad-compatible crash key interface:

class CrashKeyBreakpadTest;

namespace internal {

constexpr size_t kCrashKeyStorageKeySize = 40;
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 CRASH_KEY_EXPORT 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) {}

  CrashKeyStringImpl(const CrashKeyStringImpl&) = delete;
  CrashKeyStringImpl& operator=(const CrashKeyStringImpl&) = delete;

  void Set(std::string_view 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.
  // RAW_PTR_EXCLUSION: #global-scope
  RAW_PTR_EXCLUSION size_t* index_array_;
  size_t index_array_count_;
};

// 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 CrashKeyStringBreakpad : public internal::CrashKeyStringImpl {
 public:
  constexpr static size_t chunk_count =
      (MaxLength / internal::kCrashKeyStorageValueSize) + 1;

  // A constructor tag that can be used to initialize a C array of crash keys.
  enum class Tag { kArray };

  constexpr explicit CrashKeyStringBreakpad(const char name[])
      : internal::CrashKeyStringImpl(name, indexes_.data, chunk_count) {}

  constexpr CrashKeyStringBreakpad(const char name[], Tag tag)
      : CrashKeyStringBreakpad(name) {}

  CrashKeyStringBreakpad(const CrashKeyStringBreakpad&) = delete;
  CrashKeyStringBreakpad& operator=(const CrashKeyStringBreakpad&) = delete;

 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_;
};

template <uint32_t MaxLength>
using CrashKeyString = CrashKeyStringBreakpad<MaxLength>;

#endif  // BUILDFLAG(USE_CRASHPAD_ANNOTATION)

// 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 [[nodiscard]] ScopedCrashKeyString {
 public:
#if BUILDFLAG(USE_CRASHPAD_ANNOTATION)
  using CrashKeyType = crashpad::Annotation;
#else
  using CrashKeyType = internal::CrashKeyStringImpl;
#endif

  template <class T>
  ScopedCrashKeyString(T* crash_key, std::string_view value)
      : crash_key_(crash_key) {
    crash_key->Set(value);
  }

  ScopedCrashKeyString(const ScopedCrashKeyString&) = delete;
  ScopedCrashKeyString& operator=(const ScopedCrashKeyString&) = delete;

  ~ScopedCrashKeyString() { crash_key_->Clear(); }

 private:
  const raw_ptr<CrashKeyType> crash_key_;
};

namespace internal {
// Formats a stack trace into a string whose length will not exceed
// |max_length|. This function ensures no addresses are truncated when
// being formatted.
CRASH_KEY_EXPORT std::string FormatStackTrace(
    const base::debug::StackTrace& trace,
    size_t max_length);
}  // namespace internal

// Formats a base::debug::StackTrace as a string of space-separated hexadecimal
// numbers and stores it in a CrashKeyString.
// TODO(rsesek): When all clients use Crashpad, traces should become a first-
// class Annotation type rather than being forced through string conversion.
template <uint32_t Size>
void SetCrashKeyStringToStackTrace(CrashKeyString<Size>* key,
                                   const base::debug::StackTrace& trace) {
  std::string trace_string = internal::FormatStackTrace(trace, Size);
  key->Set(trace_string);
}

// Initializes the crash key subsystem if it is required. Calling this multiple
// times is safe (though not thread-safe) and will not result in data loss from
// crash keys set prior to the last initialization.
CRASH_KEY_EXPORT void InitializeCrashKeys();

#if defined(UNIT_TEST) || defined(CRASH_CORE_COMMON_IMPLEMENTATION)
// Returns a value for the crash key named |key_name|. For Crashpad-based
// clients, this returns the first instance found of the name. On Breakpad
// clients, oversized crash key values (those longer than
// |kCrashKeyStorageValueSize| - 1) are stored in chunks and must be retrieved
// piecewise, using syntax <key name>__1, <key name>__2, etc.
// Note: In a component build, this will only retrieve crash keys for the
// current component.
CRASH_KEY_EXPORT std::string GetCrashKeyValue(const std::string& key_name);

// Initializes the crash key subsystem with testing configuration if it is
// required.
CRASH_KEY_EXPORT void InitializeCrashKeysForTesting();

// Resets crash key state and, depending on the platform, de-initializes
// the system.
// WARNING: this does not work on Breakpad, which is used by Chrome on Linux
// (crbug.com/1041106).
CRASH_KEY_EXPORT void ResetCrashKeysForTesting();
#endif

}  // namespace crash_reporter

#endif  // COMPONENTS_CRASH_CORE_COMMON_CRASH_KEY_H_