• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "base/supports_user_data.h"
6 
7 #include "base/feature_list.h"
8 #include "base/features.h"
9 #include "base/sequence_checker.h"
10 
11 namespace base {
12 
Clone()13 std::unique_ptr<SupportsUserData::Data> SupportsUserData::Data::Clone() {
14   return nullptr;
15 }
16 
SupportsUserData()17 SupportsUserData::SupportsUserData()
18     : user_data_(FeatureList::IsEnabled(features::kSupportsUserDataFlatHashMap)
19                      ? MapVariants(FlatDataMap())
20                      : MapVariants(DataMap())) {
21   // Harmless to construct on a different execution sequence to subsequent
22   // usage.
23   DETACH_FROM_SEQUENCE(sequence_checker_);
24 }
25 
26 SupportsUserData::SupportsUserData(SupportsUserData&&) = default;
27 SupportsUserData& SupportsUserData::operator=(SupportsUserData&&) = default;
28 
GetUserData(const void * key) const29 SupportsUserData::Data* SupportsUserData::GetUserData(const void* key) const {
30   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
31   // Avoid null keys; they are too vulnerable to collision.
32   DCHECK(key);
33   return absl::visit(
34       [key](const auto& map) -> Data* {
35         auto found = map.find(key);
36         if (found != map.end()) {
37           return found->second.get();
38         }
39         return nullptr;
40       },
41       user_data_);
42 }
43 
TakeUserData(const void * key)44 std::unique_ptr<SupportsUserData::Data> SupportsUserData::TakeUserData(
45     const void* key) {
46   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
47   // Null keys are too vulnerable to collision.
48   CHECK(key);
49   return absl::visit(
50       [key](auto& map) -> std::unique_ptr<SupportsUserData::Data> {
51         auto found = map.find(key);
52         if (found != map.end()) {
53           std::unique_ptr<SupportsUserData::Data> deowned;
54           deowned.swap(found->second);
55           map.erase(key);
56           return deowned;
57         }
58         return nullptr;
59       },
60       user_data_);
61 }
62 
SetUserData(const void * key,std::unique_ptr<Data> data)63 void SupportsUserData::SetUserData(const void* key,
64                                    std::unique_ptr<Data> data) {
65   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
66   // Avoid null keys; they are too vulnerable to collision.
67   DCHECK(key);
68   if (data.get()) {
69     absl::visit([key, &data](auto& map) { map[key] = std::move(data); },
70                 user_data_);
71   } else {
72     RemoveUserData(key);
73   }
74 }
75 
RemoveUserData(const void * key)76 void SupportsUserData::RemoveUserData(const void* key) {
77   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
78   absl::visit(
79       [key](auto& map) {
80         auto it = map.find(key);
81         if (it != map.end()) {
82           // Remove the entry from the map before deleting `owned_data` to avoid
83           // reentrancy issues when `owned_data` owns `this`. Otherwise:
84           //
85           // 1. `RemoveUserData()` calls `erase()`.
86           // 2. `erase()` deletes `owned_data`.
87           // 3. `owned_data` deletes `this`.
88           //
89           // At this point, `erase()` is still on the stack even though the
90           // backing map (owned by `this`) has already been destroyed, and it
91           // may simply crash, cause a use-after-free, or any other number of
92           // interesting things.
93           auto owned_data = std::move(it->second);
94           map.erase(it);
95         }
96       },
97       user_data_);
98 }
99 
DetachFromSequence()100 void SupportsUserData::DetachFromSequence() {
101   DETACH_FROM_SEQUENCE(sequence_checker_);
102 }
103 
CloneDataFrom(const SupportsUserData & other)104 void SupportsUserData::CloneDataFrom(const SupportsUserData& other) {
105   absl::visit(
106       [this](const auto& other_map) {
107         for (const auto& data_pair : other_map) {
108           auto cloned_data = data_pair.second->Clone();
109           if (cloned_data) {
110             SetUserData(data_pair.first, std::move(cloned_data));
111           }
112         }
113       },
114       other.user_data_);
115 }
116 
~SupportsUserData()117 SupportsUserData::~SupportsUserData() {
118   if (!absl::visit([](const auto& map) { return map.empty(); }, user_data_)) {
119     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
120   }
121   MapVariants local_user_data;
122   user_data_.swap(local_user_data);
123   // Now this->user_data_ is empty, and any destructors called transitively from
124   // the destruction of |local_user_data| will see it that way instead of
125   // examining a being-destroyed object.
126 }
127 
ClearAllUserData()128 void SupportsUserData::ClearAllUserData() {
129   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
130   absl::visit([](auto& map) { map.clear(); }, user_data_);
131 }
132 
133 }  // namespace base
134