xref: /aosp_15_r20/external/cronet/base/supports_user_data.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/supports_user_data.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/sequence_checker.h"
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker namespace base {
11*6777b538SAndroid Build Coastguard Worker 
Clone()12*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SupportsUserData::Data> SupportsUserData::Data::Clone() {
13*6777b538SAndroid Build Coastguard Worker   return nullptr;
14*6777b538SAndroid Build Coastguard Worker }
15*6777b538SAndroid Build Coastguard Worker 
SupportsUserData()16*6777b538SAndroid Build Coastguard Worker SupportsUserData::SupportsUserData() {
17*6777b538SAndroid Build Coastguard Worker   // Harmless to construct on a different execution sequence to subsequent
18*6777b538SAndroid Build Coastguard Worker   // usage.
19*6777b538SAndroid Build Coastguard Worker   DETACH_FROM_SEQUENCE(sequence_checker_);
20*6777b538SAndroid Build Coastguard Worker }
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker SupportsUserData::SupportsUserData(SupportsUserData&&) = default;
23*6777b538SAndroid Build Coastguard Worker SupportsUserData& SupportsUserData::operator=(SupportsUserData&&) = default;
24*6777b538SAndroid Build Coastguard Worker 
GetUserData(const void * key) const25*6777b538SAndroid Build Coastguard Worker SupportsUserData::Data* SupportsUserData::GetUserData(const void* key) const {
26*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
27*6777b538SAndroid Build Coastguard Worker   // Avoid null keys; they are too vulnerable to collision.
28*6777b538SAndroid Build Coastguard Worker   DCHECK(key);
29*6777b538SAndroid Build Coastguard Worker   auto found = user_data_.find(key);
30*6777b538SAndroid Build Coastguard Worker   if (found != user_data_.end()) {
31*6777b538SAndroid Build Coastguard Worker     return found->second.get();
32*6777b538SAndroid Build Coastguard Worker   }
33*6777b538SAndroid Build Coastguard Worker   return nullptr;
34*6777b538SAndroid Build Coastguard Worker }
35*6777b538SAndroid Build Coastguard Worker 
TakeUserData(const void * key)36*6777b538SAndroid Build Coastguard Worker std::unique_ptr<SupportsUserData::Data> SupportsUserData::TakeUserData(
37*6777b538SAndroid Build Coastguard Worker     const void* key) {
38*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
39*6777b538SAndroid Build Coastguard Worker   // Null keys are too vulnerable to collision.
40*6777b538SAndroid Build Coastguard Worker   CHECK(key);
41*6777b538SAndroid Build Coastguard Worker   auto found = user_data_.find(key);
42*6777b538SAndroid Build Coastguard Worker   if (found != user_data_.end()) {
43*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<SupportsUserData::Data> deowned;
44*6777b538SAndroid Build Coastguard Worker     deowned.swap(found->second);
45*6777b538SAndroid Build Coastguard Worker     user_data_.erase(key);
46*6777b538SAndroid Build Coastguard Worker     return deowned;
47*6777b538SAndroid Build Coastguard Worker   }
48*6777b538SAndroid Build Coastguard Worker   return nullptr;
49*6777b538SAndroid Build Coastguard Worker }
50*6777b538SAndroid Build Coastguard Worker 
SetUserData(const void * key,std::unique_ptr<Data> data)51*6777b538SAndroid Build Coastguard Worker void SupportsUserData::SetUserData(const void* key,
52*6777b538SAndroid Build Coastguard Worker                                    std::unique_ptr<Data> data) {
53*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
54*6777b538SAndroid Build Coastguard Worker   CHECK(!in_destructor_) << "Calling SetUserData() when SupportsUserData is "
55*6777b538SAndroid Build Coastguard Worker                             "being destroyed is not supported.";
56*6777b538SAndroid Build Coastguard Worker   // Avoid null keys; they are too vulnerable to collision.
57*6777b538SAndroid Build Coastguard Worker   DCHECK(key);
58*6777b538SAndroid Build Coastguard Worker   if (data.get()) {
59*6777b538SAndroid Build Coastguard Worker     user_data_[key] = std::move(data);
60*6777b538SAndroid Build Coastguard Worker   } else {
61*6777b538SAndroid Build Coastguard Worker     RemoveUserData(key);
62*6777b538SAndroid Build Coastguard Worker   }
63*6777b538SAndroid Build Coastguard Worker }
64*6777b538SAndroid Build Coastguard Worker 
RemoveUserData(const void * key)65*6777b538SAndroid Build Coastguard Worker void SupportsUserData::RemoveUserData(const void* key) {
66*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
67*6777b538SAndroid Build Coastguard Worker   auto it = user_data_.find(key);
68*6777b538SAndroid Build Coastguard Worker   if (it != user_data_.end()) {
69*6777b538SAndroid Build Coastguard Worker     // Remove the entry from the map before deleting `owned_data` to avoid
70*6777b538SAndroid Build Coastguard Worker     // reentrancy issues when `owned_data` owns `this`. Otherwise:
71*6777b538SAndroid Build Coastguard Worker     //
72*6777b538SAndroid Build Coastguard Worker     // 1. `RemoveUserData()` calls `erase()`.
73*6777b538SAndroid Build Coastguard Worker     // 2. `erase()` deletes `owned_data`.
74*6777b538SAndroid Build Coastguard Worker     // 3. `owned_data` deletes `this`.
75*6777b538SAndroid Build Coastguard Worker     //
76*6777b538SAndroid Build Coastguard Worker     // At this point, `erase()` is still on the stack even though the
77*6777b538SAndroid Build Coastguard Worker     // backing map (owned by `this`) has already been destroyed, and it
78*6777b538SAndroid Build Coastguard Worker     // may simply crash, cause a use-after-free, or any other number of
79*6777b538SAndroid Build Coastguard Worker     // interesting things.
80*6777b538SAndroid Build Coastguard Worker     auto owned_data = std::move(it->second);
81*6777b538SAndroid Build Coastguard Worker     user_data_.erase(it);
82*6777b538SAndroid Build Coastguard Worker   }
83*6777b538SAndroid Build Coastguard Worker }
84*6777b538SAndroid Build Coastguard Worker 
DetachFromSequence()85*6777b538SAndroid Build Coastguard Worker void SupportsUserData::DetachFromSequence() {
86*6777b538SAndroid Build Coastguard Worker   DETACH_FROM_SEQUENCE(sequence_checker_);
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker 
CloneDataFrom(const SupportsUserData & other)89*6777b538SAndroid Build Coastguard Worker void SupportsUserData::CloneDataFrom(const SupportsUserData& other) {
90*6777b538SAndroid Build Coastguard Worker   for (const auto& data_pair : other.user_data_) {
91*6777b538SAndroid Build Coastguard Worker     auto cloned_data = data_pair.second->Clone();
92*6777b538SAndroid Build Coastguard Worker     if (cloned_data) {
93*6777b538SAndroid Build Coastguard Worker       SetUserData(data_pair.first, std::move(cloned_data));
94*6777b538SAndroid Build Coastguard Worker     }
95*6777b538SAndroid Build Coastguard Worker   }
96*6777b538SAndroid Build Coastguard Worker }
97*6777b538SAndroid Build Coastguard Worker 
~SupportsUserData()98*6777b538SAndroid Build Coastguard Worker SupportsUserData::~SupportsUserData() {
99*6777b538SAndroid Build Coastguard Worker   if (!user_data_.empty()) {
100*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
101*6777b538SAndroid Build Coastguard Worker   }
102*6777b538SAndroid Build Coastguard Worker   in_destructor_ = true;
103*6777b538SAndroid Build Coastguard Worker   absl::flat_hash_map<const void*, std::unique_ptr<Data>> user_data;
104*6777b538SAndroid Build Coastguard Worker   user_data_.swap(user_data);
105*6777b538SAndroid Build Coastguard Worker   // Now this->user_data_ is empty, and any destructors called transitively from
106*6777b538SAndroid Build Coastguard Worker   // the destruction of |local_user_data| will see it that way instead of
107*6777b538SAndroid Build Coastguard Worker   // examining a being-destroyed object.
108*6777b538SAndroid Build Coastguard Worker }
109*6777b538SAndroid Build Coastguard Worker 
ClearAllUserData()110*6777b538SAndroid Build Coastguard Worker void SupportsUserData::ClearAllUserData() {
111*6777b538SAndroid Build Coastguard Worker   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
112*6777b538SAndroid Build Coastguard Worker   user_data_.clear();
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker }  // namespace base
116