tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

crash_logging.h (9073B)


      1 // Copyright 2012 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_DEBUG_CRASH_LOGGING_H_
      6 #define BASE_DEBUG_CRASH_LOGGING_H_
      7 
      8 #include <stddef.h>
      9 
     10 #include <iosfwd>
     11 #include <memory>
     12 #include <type_traits>
     13 
     14 #include "base/base_export.h"
     15 #include "base/memory/raw_ptr.h"
     16 #include "base/strings/string_number_conversions.h"
     17 #include "base/strings/string_piece.h"
     18 
     19 namespace base {
     20 namespace debug {
     21 
     22 // A crash key is an annotation that is carried along with a crash report, to
     23 // provide additional debugging information beyond a stack trace. Crash keys
     24 // have a name and a string value.
     25 //
     26 // The preferred API is //components/crash/core/common:crash_key, however not
     27 // all clients can hold a direct dependency on that target. The API provided
     28 // in this file indirects the dependency and adds some convenience helpers that
     29 // make the API a bit less clunky.
     30 //
     31 // TODO(dcheng): Some of the nicer APIs should probably be upstreamed into
     32 // //components/crash.
     33 //
     34 // Preferred usage when a crash key value only needs to be set within a scope:
     35 //
     36 //   SCOPED_CRASH_KEY_STRING32("category", "name", "value");
     37 //   base::debug::DumpWithoutCrashing();
     38 //
     39 // If the crash key is pre-allocated elsewhere, but the value only needs to be
     40 // set within a scope:
     41 //
     42 //   base::debug::ScopedCrashKeyString scoper(
     43 //       GetCrashKeyForComponent(),
     44 //       "value");
     45 //
     46 // Otherwise, if the crash key needs to persist (e.g. the actual crash dump is
     47 // triggered some time later asynchronously):
     48 //
     49 //   static auto* const crash_key = base::debug::AllocateCrashKeyString(
     50 //       "name", base::debug::CrashKeySize::Size32);
     51 //   base::debug::SetCrashKeyString(crash_key, "value");
     52 //
     53 //   // Do other work before calling `base::debug::DumpWithoutCrashing()` later.
     54 //
     55 // ***WARNING***
     56 //
     57 // Do *not* write this:
     58 //
     59 //   base::debug::SetCrashKeyString(
     60 //       base::debug::AllocateCrashKeyString(
     61 //           "name", base::debug::CrashKeySize::Size32),
     62 //       "value");
     63 //
     64 // As this will leak a heap allocation every time the crash key is set!
     65 
     66 // The maximum length for a crash key's value must be one of the following
     67 // pre-determined values.
     68 enum class CrashKeySize {
     69  Size32 = 32,
     70  Size64 = 64,
     71  Size256 = 256,
     72  Size1024 = 1024,
     73 };
     74 
     75 struct CrashKeyString;
     76 
     77 // Allocates a new crash key with the specified |name| with storage for a
     78 // value up to length |size|. This will return null if the crash key system is
     79 // not initialized.
     80 //
     81 // Note: this internally allocates, so the returned pointer should always
     82 // be cached in a variable with static storage duration, e.g.:
     83 //   static auto* const crash_key = base::debug::AllocateCrashKeyString(...);
     84 BASE_EXPORT CrashKeyString* AllocateCrashKeyString(const char name[],
     85                                                   CrashKeySize size);
     86 
     87 // Stores |value| into the specified |crash_key|. The |crash_key| may be null
     88 // if AllocateCrashKeyString() returned null. If |value| is longer than the
     89 // size with which the key was allocated, it will be truncated.
     90 BASE_EXPORT void SetCrashKeyString(CrashKeyString* crash_key,
     91                                   base::StringPiece value);
     92 
     93 // Clears any value that was stored in |crash_key|. The |crash_key| may be
     94 // null.
     95 BASE_EXPORT void ClearCrashKeyString(CrashKeyString* crash_key);
     96 
     97 // Outputs current (i.e. allocated and non-empty) crash keys to `out`.
     98 BASE_EXPORT void OutputCrashKeysToStream(std::ostream& out);
     99 
    100 // A scoper that sets the specified key to value for the lifetime of the
    101 // object, and clears it on destruction.
    102 class BASE_EXPORT ScopedCrashKeyString {
    103 public:
    104  ScopedCrashKeyString(CrashKeyString* crash_key, base::StringPiece value);
    105  ScopedCrashKeyString(ScopedCrashKeyString&& other);
    106  ~ScopedCrashKeyString();
    107 
    108  // Disallow copy and assign.
    109  ScopedCrashKeyString(const ScopedCrashKeyString&) = delete;
    110  ScopedCrashKeyString& operator=(const ScopedCrashKeyString&) = delete;
    111 
    112  // Disallow move assign to keep the time at which the crash key is cleared
    113  // easy to reason about. Assigning over an existing instance would
    114  // automatically clear the key instead of at the destruction of the object.
    115  ScopedCrashKeyString& operator=(ScopedCrashKeyString&&) = delete;
    116 
    117 private:
    118  raw_ptr<CrashKeyString> crash_key_;
    119 };
    120 
    121 // Internal helpers for the SCOPED_CRASH_KEY_... helper macros defined below.
    122 //
    123 // The first static_assert that checks the length of |key_name| is a
    124 // compile-time equivalent of the DCHECK in
    125 // crash_reporter::internal::CrashKeyStringImpl::Set that restricts the name of
    126 // a crash key to 40 characters.
    127 //
    128 // The second static_assert that checks for reserved characters is a compile
    129 // time equivalent of the DCHECK in base::debug::AllocateCrashKeyString.
    130 #define SCOPED_CRASH_KEY_STRING_INTERNAL2(category, name, nonce, data,  \
    131                                          key_size)                     \
    132  static_assert(::std::size(category "-" name) < 40,                    \
    133                "Crash key names must be shorter than 40 characters."); \
    134  static_assert(::base::StringPiece(category "-" name).find(':') ==     \
    135                    ::base::StringPiece::npos,                          \
    136                "Crash key names must not contain the ':' character."); \
    137  ::base::debug::ScopedCrashKeyString scoped_crash_key_helper##nonce(   \
    138      [] {                                                              \
    139        static auto* const key = ::base::debug::AllocateCrashKeyString( \
    140            category "-" name, key_size);                               \
    141        return key;                                                     \
    142      }(),                                                              \
    143      (data))
    144 
    145 // This indirection is needed to expand __COUNTER__.
    146 #define SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, nonce, data, \
    147                                         key_size)                    \
    148  SCOPED_CRASH_KEY_STRING_INTERNAL2(category, name, nonce, data, key_size)
    149 
    150 // Helper macros for putting a local variable crash key on the stack before
    151 // causing a crash or calling CrashWithoutDumping(). `category` and `name`
    152 // should be string literals.
    153 //
    154 //   SCOPED_CRASH_KEY_STRING32("MyCategory", "key_name", "value");
    155 //
    156 // will set the crash key annotation named "MyCategory-key_name" to "value"
    157 // while in scope.
    158 #define SCOPED_CRASH_KEY_STRING32(category, name, data)                 \
    159  SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
    160                                   ::base::debug::CrashKeySize::Size32)
    161 
    162 #define SCOPED_CRASH_KEY_STRING64(category, name, data)                 \
    163  SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
    164                                   ::base::debug::CrashKeySize::Size64)
    165 
    166 #define SCOPED_CRASH_KEY_STRING256(category, name, data)                \
    167  SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
    168                                   ::base::debug::CrashKeySize::Size256)
    169 
    170 #define SCOPED_CRASH_KEY_STRING1024(category, name, data)               \
    171  SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
    172                                   ::base::debug::CrashKeySize::Size1024)
    173 
    174 #define SCOPED_CRASH_KEY_BOOL(category, name, data)                       \
    175  static_assert(std::is_same_v<std::decay_t<decltype(data)>, bool>,       \
    176                "SCOPED_CRASH_KEY_BOOL must be passed a boolean value."); \
    177  SCOPED_CRASH_KEY_STRING32(category, name, (data) ? "true" : "false")
    178 
    179 #define SCOPED_CRASH_KEY_NUMBER(category, name, data) \
    180  SCOPED_CRASH_KEY_STRING32(category, name, ::base::NumberToString(data))
    181 
    182 ////////////////////////////////////////////////////////////////////////////////
    183 // The following declarations are used to initialize the crash key system
    184 // in //base by providing implementations for the above functions.
    185 
    186 // The virtual interface that provides the implementation for the crash key
    187 // API. This is implemented by a higher-layer component, and the instance is
    188 // set using the function below.
    189 class CrashKeyImplementation {
    190 public:
    191  virtual ~CrashKeyImplementation() = default;
    192 
    193  virtual CrashKeyString* Allocate(const char name[], CrashKeySize size) = 0;
    194  virtual void Set(CrashKeyString* crash_key, base::StringPiece value) = 0;
    195  virtual void Clear(CrashKeyString* crash_key) = 0;
    196  virtual void OutputCrashKeysToStream(std::ostream& out) = 0;
    197 };
    198 
    199 // Initializes the crash key system in base by replacing the existing
    200 // implementation, if it exists, with |impl|. The |impl| is copied into base.
    201 BASE_EXPORT void SetCrashKeyImplementation(
    202    std::unique_ptr<CrashKeyImplementation> impl);
    203 
    204 // The base structure for a crash key, storing the allocation metadata.
    205 struct CrashKeyString {
    206  constexpr CrashKeyString(const char name[], CrashKeySize size)
    207      : name(name), size(size) {}
    208  const char* const name;
    209  const CrashKeySize size;
    210 };
    211 
    212 }  // namespace debug
    213 }  // namespace base
    214 
    215 #endif  // BASE_DEBUG_CRASH_LOGGING_H_