xref: /aosp_15_r20/external/tensorflow/tensorflow/core/platform/intrusive_ptr_test.cc (revision b6fb3261f9314811a0f4371741dbb8839866f948)
1 /* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include "tensorflow/core/platform/intrusive_ptr.h"
17 
18 #include "tensorflow/core/platform/refcount.h"
19 #include "tensorflow/core/platform/test.h"
20 
21 namespace tensorflow {
22 namespace core {
23 namespace {
24 
TEST(IntrusivePtr,ConstructorAddRefFalse)25 TEST(IntrusivePtr, ConstructorAddRefFalse) {
26   auto ptr = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
27   // This is needed so that the compiler does not optimize away dead code.
28   ASSERT_TRUE(ptr->RefCountIsOne());
29   // Test that there is no leak.
30 }
31 
TEST(IntrusivePtr,ConstructorAddRefTrue)32 TEST(IntrusivePtr, ConstructorAddRefTrue) {
33   auto raw = new RefCounted();
34   auto ptr = IntrusivePtr<RefCounted>(raw, /*add_ref=*/true);
35   ASSERT_FALSE(raw->RefCountIsOne());
36   raw->Unref();
37   ASSERT_TRUE(raw->RefCountIsOne());
38 }
39 
TEST(IntrusivePtr,CopyConstructor)40 TEST(IntrusivePtr, CopyConstructor) {
41   auto ptr1 = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
42   auto ptr2 = IntrusivePtr<RefCounted>(ptr1);
43   ASSERT_FALSE(ptr2->RefCountIsOne());
44 }
45 
TEST(IntrusivePtr,CopyAssignment)46 TEST(IntrusivePtr, CopyAssignment) {
47   auto ptr1 = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
48   auto raw = new RefCounted();
49   auto ptr2 = IntrusivePtr<RefCounted>(raw, /*add_ref=*/true);
50   ptr2 = ptr1;
51   ASSERT_EQ(ptr1.get(), ptr2.get());
52   ASSERT_FALSE(ptr2->RefCountIsOne());
53   ASSERT_TRUE(raw->RefCountIsOne());
54   raw->Unref();
55 }
56 
TEST(IntrusivePtr,CopyAssignmentIntoEmpty)57 TEST(IntrusivePtr, CopyAssignmentIntoEmpty) {
58   auto ptr1 = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
59   auto ptr2 = IntrusivePtr<RefCounted>();
60   ptr2 = ptr1;
61   ASSERT_FALSE(ptr2->RefCountIsOne());
62 }
63 
TEST(IntrusivePtr,MoveConstructor)64 TEST(IntrusivePtr, MoveConstructor) {
65   auto ptr1 = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
66   auto ptr2 = IntrusivePtr<RefCounted>(std::move(ptr1));
67   ASSERT_TRUE(ptr2->RefCountIsOne());
68   ASSERT_EQ(ptr1.get(), nullptr);  // NOLINT(bugprone-use-after-move)
69 }
70 
TEST(IntrusivePtr,MoveAssignment)71 TEST(IntrusivePtr, MoveAssignment) {
72   auto ptr1 = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
73   auto ptr2 = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
74   ptr2 = std::move(ptr1);
75   ASSERT_TRUE(ptr2->RefCountIsOne());
76   ASSERT_EQ(ptr1.get(), nullptr);  // NOLINT(bugprone-use-after-move)
77 }
78 
TEST(IntrusivePtr,MoveAssignmentIntoEmpty)79 TEST(IntrusivePtr, MoveAssignmentIntoEmpty) {
80   auto ptr1 = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
81   auto ptr2 = IntrusivePtr<RefCounted>();
82   ptr2 = std::move(ptr1);
83   ASSERT_TRUE(ptr2->RefCountIsOne());
84   ASSERT_EQ(ptr1.get(), nullptr);  // NOLINT(bugprone-use-after-move)
85 }
86 
TEST(IntrusivePtr,MoveAssignmentAlias)87 TEST(IntrusivePtr, MoveAssignmentAlias) {
88   auto ptr = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
89   auto& ptr_alias = ptr;
90   ptr = std::move(ptr_alias);
91   ASSERT_TRUE(ptr->RefCountIsOne());
92 }
93 
TEST(IntrusivePtr,Reset)94 TEST(IntrusivePtr, Reset) {
95   auto ptr = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
96   ptr.reset(new RefCounted(), /*add_ref=*/false);
97   ASSERT_TRUE(ptr->RefCountIsOne());
98   // Test no leak.
99 }
100 
TEST(IntrusivePtr,ResetIntoEmpty)101 TEST(IntrusivePtr, ResetIntoEmpty) {
102   auto ptr = IntrusivePtr<RefCounted>();
103   ptr.reset(new RefCounted(), /*add_ref=*/false);
104   ASSERT_TRUE(ptr->RefCountIsOne());
105   // Test no leak.
106 }
107 
TEST(IntrusivePtr,ResetAlias)108 TEST(IntrusivePtr, ResetAlias) {
109   auto ptr = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
110   ASSERT_TRUE(ptr->RefCountIsOne());
111   ptr.reset(ptr.get(), /*add_ref=*/false);  // No-op.
112   ASSERT_TRUE(ptr->RefCountIsOne());
113 }
114 
TEST(IntrusivePtr,ResetRefBeforeUnref)115 TEST(IntrusivePtr, ResetRefBeforeUnref) {
116   class Foo : public RefCounted {
117    public:
118     explicit Foo(char label, Foo* ptr = nullptr)
119         : label_(label), ptr_(ptr, false) {}
120     char label_;
121     IntrusivePtr<Foo> ptr_;
122   };
123   IntrusivePtr<Foo> x(new Foo{'a', new Foo{'b', new Foo{'c'}}}, false);
124   // This test ensures that reset calls Ref on the new handle before unreffing
125   // the current handle to avoid subtle use-after-delete bugs.
126   // Here if we were to call Unref first, we will Unref the "Foo" with the
127   // label 'b', thereby destroying it.  This will in turn Unref 'c' and destroy
128   // that. So reset would try to Ref a deleted object. Calling
129   // x->ptr_->ptr_.Ref() before x->ptr_.Unref() avoids this.
130   x->ptr_ = x->ptr_->ptr_;
131 }
132 
TEST(IntrusivePtr,ResetStealPtrBeforeUnref)133 TEST(IntrusivePtr, ResetStealPtrBeforeUnref) {
134   class Foo : public RefCounted {
135    public:
136     explicit Foo(char label, Foo* ptr = nullptr)
137         : label_(label), ptr_(ptr, false) {}
138     char label_;
139     IntrusivePtr<Foo> ptr_;
140   };
141   IntrusivePtr<Foo> x(new Foo{'a', new Foo{'b', new Foo{'c'}}}, false);
142   // This test ensures that move assignment clears the handle_ of the moved
143   // object before Unreffing the current handle_.
144   x->ptr_ = std::move(x->ptr_->ptr_);
145 }
146 
TEST(IntrusivePtr,Detach)147 TEST(IntrusivePtr, Detach) {
148   auto ptr = IntrusivePtr<RefCounted>(new RefCounted(), /*add_ref=*/false);
149   ASSERT_TRUE(ptr->RefCountIsOne());
150   auto raw = ptr.detach();
151   ASSERT_TRUE(raw->RefCountIsOne());
152   raw->Unref();
153 }
154 }  // namespace
155 }  // namespace core
156 }  // namespace tensorflow
157