tor-browser

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

status_internal.cc (8583B)


      1 // Copyright 2023 The Abseil Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/status/internal/status_internal.h"
     16 
     17 #include <atomic>
     18 #include <cassert>
     19 #include <cstddef>
     20 #include <cstdint>
     21 #include <cstdio>
     22 #include <cstring>
     23 #include <memory>
     24 #include <string>
     25 #include <utility>
     26 
     27 #include "absl/base/attributes.h"
     28 #include "absl/base/config.h"
     29 #include "absl/base/macros.h"
     30 #include "absl/base/nullability.h"
     31 #include "absl/debugging/leak_check.h"
     32 #include "absl/debugging/stacktrace.h"
     33 #include "absl/debugging/symbolize.h"
     34 #include "absl/memory/memory.h"
     35 #include "absl/status/status.h"
     36 #include "absl/status/status_payload_printer.h"
     37 #include "absl/strings/cord.h"
     38 #include "absl/strings/escaping.h"
     39 #include "absl/strings/str_cat.h"
     40 #include "absl/strings/str_format.h"
     41 #include "absl/strings/str_split.h"
     42 #include "absl/strings/string_view.h"
     43 #include "absl/types/optional.h"
     44 
     45 namespace absl {
     46 ABSL_NAMESPACE_BEGIN
     47 namespace status_internal {
     48 
     49 void StatusRep::Unref() const {
     50  // Fast path: if ref==1, there is no need for a RefCountDec (since
     51  // this is the only reference and therefore no other thread is
     52  // allowed to be mucking with r).
     53  if (ref_.load(std::memory_order_acquire) == 1 ||
     54      ref_.fetch_sub(1, std::memory_order_acq_rel) - 1 == 0) {
     55    delete this;
     56  }
     57 }
     58 
     59 static absl::optional<size_t> FindPayloadIndexByUrl(
     60    const Payloads* payloads, absl::string_view type_url) {
     61  if (payloads == nullptr) return absl::nullopt;
     62 
     63  for (size_t i = 0; i < payloads->size(); ++i) {
     64    if ((*payloads)[i].type_url == type_url) return i;
     65  }
     66 
     67  return absl::nullopt;
     68 }
     69 
     70 absl::optional<absl::Cord> StatusRep::GetPayload(
     71    absl::string_view type_url) const {
     72  absl::optional<size_t> index =
     73      status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url);
     74  if (index.has_value()) return (*payloads_)[index.value()].payload;
     75 
     76  return absl::nullopt;
     77 }
     78 
     79 void StatusRep::SetPayload(absl::string_view type_url, absl::Cord payload) {
     80  if (payloads_ == nullptr) {
     81    payloads_ = absl::make_unique<status_internal::Payloads>();
     82  }
     83 
     84  absl::optional<size_t> index =
     85      status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url);
     86  if (index.has_value()) {
     87    (*payloads_)[index.value()].payload = std::move(payload);
     88    return;
     89  }
     90 
     91  payloads_->push_back({std::string(type_url), std::move(payload)});
     92 }
     93 
     94 StatusRep::EraseResult StatusRep::ErasePayload(absl::string_view type_url) {
     95  absl::optional<size_t> index =
     96      status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url);
     97  if (!index.has_value()) return {false, Status::PointerToRep(this)};
     98  payloads_->erase(payloads_->begin() + index.value());
     99  if (payloads_->empty() && message_.empty()) {
    100    // Special case: If this can be represented inlined, it MUST be inlined
    101    // (== depends on this behavior).
    102    EraseResult result = {true, Status::CodeToInlinedRep(code_)};
    103    Unref();
    104    return result;
    105  }
    106  return {true, Status::PointerToRep(this)};
    107 }
    108 
    109 void StatusRep::ForEachPayload(
    110    absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor)
    111    const {
    112  if (auto* payloads = payloads_.get()) {
    113    bool in_reverse =
    114        payloads->size() > 1 && reinterpret_cast<uintptr_t>(payloads) % 13 > 6;
    115 
    116    for (size_t index = 0; index < payloads->size(); ++index) {
    117      const auto& elem =
    118          (*payloads)[in_reverse ? payloads->size() - 1 - index : index];
    119 
    120 #ifdef NDEBUG
    121      visitor(elem.type_url, elem.payload);
    122 #else
    123      // In debug mode invalidate the type url to prevent users from relying on
    124      // this string lifetime.
    125 
    126      // NOLINTNEXTLINE intentional extra conversion to force temporary.
    127      visitor(std::string(elem.type_url), elem.payload);
    128 #endif  // NDEBUG
    129    }
    130  }
    131 }
    132 
    133 std::string StatusRep::ToString(StatusToStringMode mode) const {
    134  std::string text;
    135  absl::StrAppend(&text, absl::StatusCodeToString(code()), ": ", message());
    136 
    137  const bool with_payload = (mode & StatusToStringMode::kWithPayload) ==
    138                            StatusToStringMode::kWithPayload;
    139 
    140  if (with_payload) {
    141    status_internal::StatusPayloadPrinter printer =
    142        status_internal::GetStatusPayloadPrinter();
    143    this->ForEachPayload([&](absl::string_view type_url,
    144                             const absl::Cord& payload) {
    145      absl::optional<std::string> result;
    146      if (printer) result = printer(type_url, payload);
    147      absl::StrAppend(
    148          &text, " [", type_url, "='",
    149          result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
    150          "']");
    151    });
    152  }
    153 
    154  return text;
    155 }
    156 
    157 bool StatusRep::operator==(const StatusRep& other) const {
    158  assert(this != &other);
    159  if (code_ != other.code_) return false;
    160  if (message_ != other.message_) return false;
    161  const status_internal::Payloads* this_payloads = payloads_.get();
    162  const status_internal::Payloads* other_payloads = other.payloads_.get();
    163 
    164  const status_internal::Payloads no_payloads;
    165  const status_internal::Payloads* larger_payloads =
    166      this_payloads ? this_payloads : &no_payloads;
    167  const status_internal::Payloads* smaller_payloads =
    168      other_payloads ? other_payloads : &no_payloads;
    169  if (larger_payloads->size() < smaller_payloads->size()) {
    170    std::swap(larger_payloads, smaller_payloads);
    171  }
    172  if ((larger_payloads->size() - smaller_payloads->size()) > 1) return false;
    173  // Payloads can be ordered differently, so we can't just compare payload
    174  // vectors.
    175  for (const auto& payload : *larger_payloads) {
    176 
    177    bool found = false;
    178    for (const auto& other_payload : *smaller_payloads) {
    179      if (payload.type_url == other_payload.type_url) {
    180        if (payload.payload != other_payload.payload) {
    181          return false;
    182        }
    183        found = true;
    184        break;
    185      }
    186    }
    187    if (!found) return false;
    188  }
    189  return true;
    190 }
    191 
    192 absl::Nonnull<StatusRep*> StatusRep::CloneAndUnref() const {
    193  // Optimization: no need to create a clone if we already have a refcount of 1.
    194  if (ref_.load(std::memory_order_acquire) == 1) {
    195    // All StatusRep instances are heap allocated and mutable, therefore this
    196    // const_cast will never cast away const from a stack instance.
    197    //
    198    // CloneAndUnref is the only method that doesn't involve an external cast to
    199    // get a mutable StatusRep* from the uintptr_t rep stored in Status.
    200    return const_cast<StatusRep*>(this);
    201  }
    202  std::unique_ptr<status_internal::Payloads> payloads;
    203  if (payloads_) {
    204    payloads = absl::make_unique<status_internal::Payloads>(*payloads_);
    205  }
    206  auto* new_rep = new StatusRep(code_, message_, std::move(payloads));
    207  Unref();
    208  return new_rep;
    209 }
    210 
    211 // Convert canonical code to a value known to this binary.
    212 absl::StatusCode MapToLocalCode(int value) {
    213  absl::StatusCode code = static_cast<absl::StatusCode>(value);
    214  switch (code) {
    215    case absl::StatusCode::kOk:
    216    case absl::StatusCode::kCancelled:
    217    case absl::StatusCode::kUnknown:
    218    case absl::StatusCode::kInvalidArgument:
    219    case absl::StatusCode::kDeadlineExceeded:
    220    case absl::StatusCode::kNotFound:
    221    case absl::StatusCode::kAlreadyExists:
    222    case absl::StatusCode::kPermissionDenied:
    223    case absl::StatusCode::kResourceExhausted:
    224    case absl::StatusCode::kFailedPrecondition:
    225    case absl::StatusCode::kAborted:
    226    case absl::StatusCode::kOutOfRange:
    227    case absl::StatusCode::kUnimplemented:
    228    case absl::StatusCode::kInternal:
    229    case absl::StatusCode::kUnavailable:
    230    case absl::StatusCode::kDataLoss:
    231    case absl::StatusCode::kUnauthenticated:
    232      return code;
    233    default:
    234      return absl::StatusCode::kUnknown;
    235  }
    236 }
    237 
    238 absl::Nonnull<const char*> MakeCheckFailString(
    239    absl::Nonnull<const absl::Status*> status,
    240    absl::Nonnull<const char*> prefix) {
    241  // There's no need to free this string since the process is crashing.
    242  return absl::IgnoreLeak(
    243             new std::string(absl::StrCat(
    244                 prefix, " (",
    245                 status->ToString(StatusToStringMode::kWithEverything), ")")))
    246      ->c_str();
    247 }
    248 
    249 }  // namespace status_internal
    250 
    251 ABSL_NAMESPACE_END
    252 }  // namespace absl