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.
5 #include "base/supports_user_data.h"
7 #include "base/feature_list.h"
8 #include "base/sequence_checker.h"
12 std::unique_ptr<SupportsUserData::Data> SupportsUserData::Data::Clone() {
16 SupportsUserData::SupportsUserData() {
17 // Harmless to construct on a different execution sequence to subsequent
19 DETACH_FROM_SEQUENCE(sequence_checker_);
22 SupportsUserData::SupportsUserData(SupportsUserData&&) = default;
23 SupportsUserData& SupportsUserData::operator=(SupportsUserData&&) = default;
25 SupportsUserData::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.
29 auto found = user_data_.find(key);
30 if (found != user_data_.end()) {
31 return found->second.get();
36 std::unique_ptr<SupportsUserData::Data> SupportsUserData::TakeUserData(
38 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
39 // Null keys are too vulnerable to collision.
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);
51 void 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.
59 user_data_[key] = std::move(data);
65 void 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:
72 // 1. `RemoveUserData()` calls `erase()`.
73 // 2. `erase()` deletes `owned_data`.
74 // 3. `owned_data` deletes `this`.
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);
85 void SupportsUserData::DetachFromSequence() {
86 DETACH_FROM_SEQUENCE(sequence_checker_);
89 void SupportsUserData::CloneDataFrom(const SupportsUserData& other) {
90 for (const auto& data_pair : other.user_data_) {
91 auto cloned_data = data_pair.second->Clone();
93 SetUserData(data_pair.first, std::move(cloned_data));
98 SupportsUserData::~SupportsUserData() {
99 if (!user_data_.empty()) {
100 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
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.
110 void SupportsUserData::ClearAllUserData() {
111 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);