xref: /aosp_15_r20/external/cronet/base/win/scoped_handle.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_WIN_SCOPED_HANDLE_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_WIN_SCOPED_HANDLE_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <ostream>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/dcheck_is_on.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/gtest_prod_util.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/win/windows_types.h"
16*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker // TODO(rvargas): remove this with the rest of the verifier.
19*6777b538SAndroid Build Coastguard Worker #if defined(COMPILER_MSVC)
20*6777b538SAndroid Build Coastguard Worker #include <intrin.h>
21*6777b538SAndroid Build Coastguard Worker #define BASE_WIN_GET_CALLER _ReturnAddress()
22*6777b538SAndroid Build Coastguard Worker #elif defined(COMPILER_GCC)
23*6777b538SAndroid Build Coastguard Worker #define BASE_WIN_GET_CALLER \
24*6777b538SAndroid Build Coastguard Worker   __builtin_extract_return_addr(__builtin_return_address(0))
25*6777b538SAndroid Build Coastguard Worker #endif
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker namespace base {
28*6777b538SAndroid Build Coastguard Worker namespace win {
29*6777b538SAndroid Build Coastguard Worker 
30*6777b538SAndroid Build Coastguard Worker enum class HandleOperation {
31*6777b538SAndroid Build Coastguard Worker   kHandleAlreadyTracked,
32*6777b538SAndroid Build Coastguard Worker   kCloseHandleNotTracked,
33*6777b538SAndroid Build Coastguard Worker   kCloseHandleNotOwner,
34*6777b538SAndroid Build Coastguard Worker   kCloseHandleHook,
35*6777b538SAndroid Build Coastguard Worker   kDuplicateHandleHook
36*6777b538SAndroid Build Coastguard Worker };
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, HandleOperation operation);
39*6777b538SAndroid Build Coastguard Worker 
40*6777b538SAndroid Build Coastguard Worker // Generic wrapper for raw handles that takes care of closing handles
41*6777b538SAndroid Build Coastguard Worker // automatically. The class interface follows the style of
42*6777b538SAndroid Build Coastguard Worker // the ScopedFILE class with two additions:
43*6777b538SAndroid Build Coastguard Worker //   - IsValid() method can tolerate multiple invalid handle values such as NULL
44*6777b538SAndroid Build Coastguard Worker //     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
45*6777b538SAndroid Build Coastguard Worker //   - Set() (and the constructors and assignment operators that call it)
46*6777b538SAndroid Build Coastguard Worker //     preserve the Windows LastError code. This ensures that GetLastError() can
47*6777b538SAndroid Build Coastguard Worker //     be called after stashing a handle in a GenericScopedHandle object. Doing
48*6777b538SAndroid Build Coastguard Worker //     this explicitly is necessary because of bug 528394 and VC++ 2015.
49*6777b538SAndroid Build Coastguard Worker template <class Traits, class Verifier>
50*6777b538SAndroid Build Coastguard Worker class GenericScopedHandle {
51*6777b538SAndroid Build Coastguard Worker  public:
52*6777b538SAndroid Build Coastguard Worker   using Handle = typename Traits::Handle;
53*6777b538SAndroid Build Coastguard Worker 
GenericScopedHandle()54*6777b538SAndroid Build Coastguard Worker   GenericScopedHandle() : handle_(Traits::NullHandle()) {}
55*6777b538SAndroid Build Coastguard Worker 
GenericScopedHandle(Handle handle)56*6777b538SAndroid Build Coastguard Worker   explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
57*6777b538SAndroid Build Coastguard Worker     Set(handle);
58*6777b538SAndroid Build Coastguard Worker   }
59*6777b538SAndroid Build Coastguard Worker 
GenericScopedHandle(GenericScopedHandle && other)60*6777b538SAndroid Build Coastguard Worker   GenericScopedHandle(GenericScopedHandle&& other)
61*6777b538SAndroid Build Coastguard Worker       : handle_(Traits::NullHandle()) {
62*6777b538SAndroid Build Coastguard Worker     Set(other.Take());
63*6777b538SAndroid Build Coastguard Worker   }
64*6777b538SAndroid Build Coastguard Worker 
65*6777b538SAndroid Build Coastguard Worker   GenericScopedHandle(const GenericScopedHandle&) = delete;
66*6777b538SAndroid Build Coastguard Worker   GenericScopedHandle& operator=(const GenericScopedHandle&) = delete;
67*6777b538SAndroid Build Coastguard Worker 
~GenericScopedHandle()68*6777b538SAndroid Build Coastguard Worker   ~GenericScopedHandle() { Close(); }
69*6777b538SAndroid Build Coastguard Worker 
is_valid()70*6777b538SAndroid Build Coastguard Worker   bool is_valid() const { return Traits::IsHandleValid(handle_); }
71*6777b538SAndroid Build Coastguard Worker 
72*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1291793): Migrate callers to is_valid().
IsValid()73*6777b538SAndroid Build Coastguard Worker   bool IsValid() const { return is_valid(); }
74*6777b538SAndroid Build Coastguard Worker 
75*6777b538SAndroid Build Coastguard Worker   GenericScopedHandle& operator=(GenericScopedHandle&& other) {
76*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(this, &other);
77*6777b538SAndroid Build Coastguard Worker     Set(other.Take());
78*6777b538SAndroid Build Coastguard Worker     return *this;
79*6777b538SAndroid Build Coastguard Worker   }
80*6777b538SAndroid Build Coastguard Worker 
Set(Handle handle)81*6777b538SAndroid Build Coastguard Worker   void Set(Handle handle) {
82*6777b538SAndroid Build Coastguard Worker     if (handle_ != handle) {
83*6777b538SAndroid Build Coastguard Worker       // Preserve old LastError to avoid bug 528394.
84*6777b538SAndroid Build Coastguard Worker       auto last_error = ::GetLastError();
85*6777b538SAndroid Build Coastguard Worker       Close();
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker       if (Traits::IsHandleValid(handle)) {
88*6777b538SAndroid Build Coastguard Worker         handle_ = handle;
89*6777b538SAndroid Build Coastguard Worker         Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
90*6777b538SAndroid Build Coastguard Worker                                 GetProgramCounter());
91*6777b538SAndroid Build Coastguard Worker       }
92*6777b538SAndroid Build Coastguard Worker       ::SetLastError(last_error);
93*6777b538SAndroid Build Coastguard Worker     }
94*6777b538SAndroid Build Coastguard Worker   }
95*6777b538SAndroid Build Coastguard Worker 
get()96*6777b538SAndroid Build Coastguard Worker   Handle get() const { return handle_; }
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1291793): Migrate callers to get().
Get()99*6777b538SAndroid Build Coastguard Worker   Handle Get() const { return get(); }
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker   // Transfers ownership away from this object.
release()102*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] Handle release() {
103*6777b538SAndroid Build Coastguard Worker     Handle temp = handle_;
104*6777b538SAndroid Build Coastguard Worker     handle_ = Traits::NullHandle();
105*6777b538SAndroid Build Coastguard Worker     if (Traits::IsHandleValid(temp)) {
106*6777b538SAndroid Build Coastguard Worker       Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER,
107*6777b538SAndroid Build Coastguard Worker                              GetProgramCounter());
108*6777b538SAndroid Build Coastguard Worker     }
109*6777b538SAndroid Build Coastguard Worker     return temp;
110*6777b538SAndroid Build Coastguard Worker   }
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1291793): Migrate callers to release().
Take()113*6777b538SAndroid Build Coastguard Worker   [[nodiscard]] Handle Take() { return release(); }
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker   // Explicitly closes the owned handle.
Close()116*6777b538SAndroid Build Coastguard Worker   void Close() {
117*6777b538SAndroid Build Coastguard Worker     if (Traits::IsHandleValid(handle_)) {
118*6777b538SAndroid Build Coastguard Worker       Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER,
119*6777b538SAndroid Build Coastguard Worker                              GetProgramCounter());
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker       Traits::CloseHandle(handle_);
122*6777b538SAndroid Build Coastguard Worker       handle_ = Traits::NullHandle();
123*6777b538SAndroid Build Coastguard Worker     }
124*6777b538SAndroid Build Coastguard Worker   }
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker  private:
127*6777b538SAndroid Build Coastguard Worker   FRIEND_TEST_ALL_PREFIXES(ScopedHandleDeathTest, HandleVerifierWrongOwner);
128*6777b538SAndroid Build Coastguard Worker   FRIEND_TEST_ALL_PREFIXES(ScopedHandleDeathTest,
129*6777b538SAndroid Build Coastguard Worker                            HandleVerifierUntrackedHandle);
130*6777b538SAndroid Build Coastguard Worker   Handle handle_;
131*6777b538SAndroid Build Coastguard Worker };
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker #undef BASE_WIN_GET_CALLER
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker // The traits class for Win32 handles that can be closed via CloseHandle() API.
136*6777b538SAndroid Build Coastguard Worker class HandleTraits {
137*6777b538SAndroid Build Coastguard Worker  public:
138*6777b538SAndroid Build Coastguard Worker   using Handle = HANDLE;
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker   HandleTraits() = delete;
141*6777b538SAndroid Build Coastguard Worker   HandleTraits(const HandleTraits&) = delete;
142*6777b538SAndroid Build Coastguard Worker   HandleTraits& operator=(const HandleTraits&) = delete;
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker   // Closes the handle.
145*6777b538SAndroid Build Coastguard Worker   static bool BASE_EXPORT CloseHandle(HANDLE handle);
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   // Returns true if the handle value is valid.
IsHandleValid(HANDLE handle)148*6777b538SAndroid Build Coastguard Worker   static bool IsHandleValid(HANDLE handle) {
149*6777b538SAndroid Build Coastguard Worker     return handle != nullptr && handle != INVALID_HANDLE_VALUE;
150*6777b538SAndroid Build Coastguard Worker   }
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   // Returns NULL handle value.
NullHandle()153*6777b538SAndroid Build Coastguard Worker   static HANDLE NullHandle() { return nullptr; }
154*6777b538SAndroid Build Coastguard Worker };
155*6777b538SAndroid Build Coastguard Worker 
156*6777b538SAndroid Build Coastguard Worker // Do-nothing verifier.
157*6777b538SAndroid Build Coastguard Worker class DummyVerifierTraits {
158*6777b538SAndroid Build Coastguard Worker  public:
159*6777b538SAndroid Build Coastguard Worker   using Handle = HANDLE;
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker   DummyVerifierTraits() = delete;
162*6777b538SAndroid Build Coastguard Worker   DummyVerifierTraits(const DummyVerifierTraits&) = delete;
163*6777b538SAndroid Build Coastguard Worker   DummyVerifierTraits& operator=(const DummyVerifierTraits&) = delete;
164*6777b538SAndroid Build Coastguard Worker 
StartTracking(HANDLE handle,const void * owner,const void * pc1,const void * pc2)165*6777b538SAndroid Build Coastguard Worker   static void StartTracking(HANDLE handle,
166*6777b538SAndroid Build Coastguard Worker                             const void* owner,
167*6777b538SAndroid Build Coastguard Worker                             const void* pc1,
168*6777b538SAndroid Build Coastguard Worker                             const void* pc2) {}
StopTracking(HANDLE handle,const void * owner,const void * pc1,const void * pc2)169*6777b538SAndroid Build Coastguard Worker   static void StopTracking(HANDLE handle,
170*6777b538SAndroid Build Coastguard Worker                            const void* owner,
171*6777b538SAndroid Build Coastguard Worker                            const void* pc1,
172*6777b538SAndroid Build Coastguard Worker                            const void* pc2) {}
173*6777b538SAndroid Build Coastguard Worker };
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker // Performs actual run-time tracking.
176*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT VerifierTraits {
177*6777b538SAndroid Build Coastguard Worker  public:
178*6777b538SAndroid Build Coastguard Worker   using Handle = HANDLE;
179*6777b538SAndroid Build Coastguard Worker 
180*6777b538SAndroid Build Coastguard Worker   VerifierTraits() = delete;
181*6777b538SAndroid Build Coastguard Worker   VerifierTraits(const VerifierTraits&) = delete;
182*6777b538SAndroid Build Coastguard Worker   VerifierTraits& operator=(const VerifierTraits&) = delete;
183*6777b538SAndroid Build Coastguard Worker 
184*6777b538SAndroid Build Coastguard Worker   static void StartTracking(HANDLE handle,
185*6777b538SAndroid Build Coastguard Worker                             const void* owner,
186*6777b538SAndroid Build Coastguard Worker                             const void* pc1,
187*6777b538SAndroid Build Coastguard Worker                             const void* pc2);
188*6777b538SAndroid Build Coastguard Worker   static void StopTracking(HANDLE handle,
189*6777b538SAndroid Build Coastguard Worker                            const void* owner,
190*6777b538SAndroid Build Coastguard Worker                            const void* pc1,
191*6777b538SAndroid Build Coastguard Worker                            const void* pc2);
192*6777b538SAndroid Build Coastguard Worker };
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker using UncheckedScopedHandle =
195*6777b538SAndroid Build Coastguard Worker     GenericScopedHandle<HandleTraits, DummyVerifierTraits>;
196*6777b538SAndroid Build Coastguard Worker using CheckedScopedHandle = GenericScopedHandle<HandleTraits, VerifierTraits>;
197*6777b538SAndroid Build Coastguard Worker 
198*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
199*6777b538SAndroid Build Coastguard Worker using ScopedHandle = CheckedScopedHandle;
200*6777b538SAndroid Build Coastguard Worker #else
201*6777b538SAndroid Build Coastguard Worker using ScopedHandle = UncheckedScopedHandle;
202*6777b538SAndroid Build Coastguard Worker #endif
203*6777b538SAndroid Build Coastguard Worker 
204*6777b538SAndroid Build Coastguard Worker // This function may be called by the embedder to disable the use of
205*6777b538SAndroid Build Coastguard Worker // VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used
206*6777b538SAndroid Build Coastguard Worker // for ScopedHandle.
207*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void DisableHandleVerifier();
208*6777b538SAndroid Build Coastguard Worker 
209*6777b538SAndroid Build Coastguard Worker // This should be called whenever the OS is closing a handle, if extended
210*6777b538SAndroid Build Coastguard Worker // verification of improper handle closing is desired. If |handle| is being
211*6777b538SAndroid Build Coastguard Worker // tracked by the handle verifier and ScopedHandle is not the one closing it,
212*6777b538SAndroid Build Coastguard Worker // a CHECK is generated.
213*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void OnHandleBeingClosed(HANDLE handle, HandleOperation operation);
214*6777b538SAndroid Build Coastguard Worker 
215*6777b538SAndroid Build Coastguard Worker }  // namespace win
216*6777b538SAndroid Build Coastguard Worker }  // namespace base
217*6777b538SAndroid Build Coastguard Worker 
218*6777b538SAndroid Build Coastguard Worker #endif  // BASE_WIN_SCOPED_HANDLE_H_
219