1 // Copyright 2014 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/features.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/memory/raw_ptr.h"
10 #include "base/memory/raw_ref.h"
11 #include "base/test/gtest_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace base {
15 namespace {
16
17 struct TestSupportsUserData : public SupportsUserData {
18 // Make ClearAllUserData public so tests can access it.
19 using SupportsUserData::ClearAllUserData;
20 };
21
22 struct UsesItself : public SupportsUserData::Data {
UsesItselfbase::__anon16e841650111::UsesItself23 UsesItself(SupportsUserData* supports_user_data, const void* key)
24 : supports_user_data_(supports_user_data),
25 key_(key) {
26 }
27
~UsesItselfbase::__anon16e841650111::UsesItself28 ~UsesItself() override {
29 EXPECT_EQ(nullptr, supports_user_data_->GetUserData(key_));
30 }
31
32 raw_ptr<SupportsUserData> supports_user_data_;
33 raw_ptr<const void> key_;
34 };
35
36 using SupportsUserDataTest = ::testing::Test;
37
TEST_F(SupportsUserDataTest,ClearWorksRecursively)38 TEST_F(SupportsUserDataTest, ClearWorksRecursively) {
39 char key = 0; // Must outlive `supports_user_data`.
40 TestSupportsUserData supports_user_data;
41 supports_user_data.SetUserData(
42 &key, std::make_unique<UsesItself>(&supports_user_data, &key));
43 // Destruction of supports_user_data runs the actual test.
44 }
45
46 struct TestData : public SupportsUserData::Data {};
47
TEST_F(SupportsUserDataTest,Movable)48 TEST_F(SupportsUserDataTest, Movable) {
49 TestSupportsUserData supports_user_data_1;
50 char key1 = 0;
51 supports_user_data_1.SetUserData(&key1, std::make_unique<TestData>());
52 void* data_1_ptr = supports_user_data_1.GetUserData(&key1);
53
54 TestSupportsUserData supports_user_data_2;
55 char key2 = 0;
56 supports_user_data_2.SetUserData(&key2, std::make_unique<TestData>());
57
58 supports_user_data_2 = std::move(supports_user_data_1);
59
60 EXPECT_EQ(data_1_ptr, supports_user_data_2.GetUserData(&key1));
61 EXPECT_EQ(nullptr, supports_user_data_2.GetUserData(&key2));
62 }
63
TEST_F(SupportsUserDataTest,ClearAllUserData)64 TEST_F(SupportsUserDataTest, ClearAllUserData) {
65 TestSupportsUserData supports_user_data;
66 char key1 = 0;
67 supports_user_data.SetUserData(&key1, std::make_unique<TestData>());
68 char key2 = 0;
69 supports_user_data.SetUserData(&key2, std::make_unique<TestData>());
70
71 EXPECT_TRUE(supports_user_data.GetUserData(&key1));
72 EXPECT_TRUE(supports_user_data.GetUserData(&key2));
73
74 supports_user_data.ClearAllUserData();
75
76 EXPECT_FALSE(supports_user_data.GetUserData(&key1));
77 EXPECT_FALSE(supports_user_data.GetUserData(&key2));
78 }
79
TEST_F(SupportsUserDataTest,TakeUserData)80 TEST_F(SupportsUserDataTest, TakeUserData) {
81 TestSupportsUserData supports_user_data;
82 char key1 = 0;
83 supports_user_data.SetUserData(&key1, std::make_unique<TestData>());
84
85 TestSupportsUserData::Data* data1_ptr = supports_user_data.GetUserData(&key1);
86 EXPECT_NE(data1_ptr, nullptr);
87
88 char wrong_key = 0;
89 EXPECT_FALSE(supports_user_data.TakeUserData(&wrong_key));
90
91 EXPECT_EQ(supports_user_data.GetUserData(&key1), data1_ptr);
92
93 std::unique_ptr<TestSupportsUserData::Data> data1 =
94 supports_user_data.TakeUserData(&key1);
95 EXPECT_EQ(data1.get(), data1_ptr);
96
97 EXPECT_FALSE(supports_user_data.GetUserData(&key1));
98 EXPECT_FALSE(supports_user_data.TakeUserData(&key1));
99 }
100
101 class DataOwnsSupportsUserData : public SupportsUserData::Data {
102 public:
supports_user_data()103 TestSupportsUserData* supports_user_data() { return &supports_user_data_; }
104
105 private:
106 TestSupportsUserData supports_user_data_;
107 };
108
109 // Tests that removing a `SupportsUserData::Data` that owns a `SupportsUserData`
110 // does not crash.
TEST_F(SupportsUserDataTest,ReentrantRemoveUserData)111 TEST_F(SupportsUserDataTest, ReentrantRemoveUserData) {
112 DataOwnsSupportsUserData* data = new DataOwnsSupportsUserData;
113 char key = 0;
114 data->supports_user_data()->SetUserData(&key, WrapUnique(data));
115 data->supports_user_data()->RemoveUserData(&key);
116 }
117
TEST_F(SupportsUserDataTest,ReentrantSetUserDataDuringRemoval)118 TEST_F(SupportsUserDataTest, ReentrantSetUserDataDuringRemoval) {
119 static const char kKey = 0;
120
121 class ProblematicSet : public SupportsUserData::Data {
122 public:
123 explicit ProblematicSet(const void* const key,
124 TestSupportsUserData& supports_user_data)
125 : key_(key), supports_user_data_(supports_user_data) {}
126
127 ~ProblematicSet() override {
128 supports_user_data_->SetUserData(
129 key_, std::make_unique<ProblematicSet>(key_, *supports_user_data_));
130 }
131
132 private:
133 const raw_ptr<const void> key_;
134 raw_ref<TestSupportsUserData> supports_user_data_;
135 };
136 {
137 std::optional<TestSupportsUserData> supports_user_data;
138 supports_user_data.emplace();
139 // This awkward construction is required since death tests are typically
140 // implemented using `fork()`, so calling `SetUserData()` outside the
141 // `EXPECT_CHECK_DEATH()` macro will also crash the process that's trying to
142 // observe the crash.
143 EXPECT_CHECK_DEATH([&] {
144 supports_user_data->SetUserData(
145 &kKey, std::make_unique<ProblematicSet>(&kKey, *supports_user_data));
146 // Triggers the reentrant attempt to call `SetUserData()` during
147 // destruction.
148 supports_user_data.reset();
149 }());
150 }
151 }
152
153 } // namespace
154 } // namespace base
155