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