• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_WIN_SCOPED_HANDLE_H_
6 #define BASE_WIN_SCOPED_HANDLE_H_
7 
8 #include <windows.h>
9 
10 #include "base/gtest_prod_util.h"
11 #include "base/logging.h"
12 
13 // TODO(rvargas): remove this with the rest of the verifier.
14 #if defined(COMPILER_MSVC)
15 #include <intrin.h>
16 #define BASE_WIN_GET_CALLER _ReturnAddress()
17 #elif defined(COMPILER_GCC)
18 #define BASE_WIN_GET_CALLER \
19   __builtin_extract_return_addr(\ __builtin_return_address(0))
20 #endif
21 
22 namespace base {
23 namespace win {
24 
25 // Generic wrapper for raw handles that takes care of closing handles
26 // automatically. The class interface follows the style of
27 // the ScopedFILE class with two additions:
28 //   - IsValid() method can tolerate multiple invalid handle values such as NULL
29 //     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
30 //   - Set() (and the constructors and assignment operators that call it)
31 //     preserve the Windows LastError code. This ensures that GetLastError() can
32 //     be called after stashing a handle in a GenericScopedHandle object. Doing
33 //     this explicitly is necessary because of bug 528394 and VC++ 2015.
34 template <class Traits, class Verifier>
35 class GenericScopedHandle {
36  public:
37   typedef typename Traits::Handle Handle;
38 
GenericScopedHandle()39   GenericScopedHandle() : handle_(Traits::NullHandle()) {}
40 
GenericScopedHandle(Handle handle)41   explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
42     Set(handle);
43   }
44 
GenericScopedHandle(GenericScopedHandle && other)45   GenericScopedHandle(GenericScopedHandle&& other)
46       : handle_(Traits::NullHandle()) {
47     Set(other.Take());
48   }
49 
~GenericScopedHandle()50   ~GenericScopedHandle() { Close(); }
51 
IsValid()52   bool IsValid() const { return Traits::IsHandleValid(handle_); }
53 
54   GenericScopedHandle& operator=(GenericScopedHandle&& other) {
55     DCHECK_NE(this, &other);
56     Set(other.Take());
57     return *this;
58   }
59 
Set(Handle handle)60   void Set(Handle handle) {
61     if (handle_ != handle) {
62       // Preserve old LastError to avoid bug 528394.
63       auto last_error = ::GetLastError();
64       Close();
65 
66       if (Traits::IsHandleValid(handle)) {
67         handle_ = handle;
68       }
69       ::SetLastError(last_error);
70     }
71   }
72 
Get()73   Handle Get() const { return handle_; }
74 
75   // Transfers ownership away from this object.
Take()76   Handle Take() {
77     Handle temp = handle_;
78     handle_ = Traits::NullHandle();
79     return temp;
80   }
81 
82   // Explicitly closes the owned handle.
Close()83   void Close() {
84     if (Traits::IsHandleValid(handle_)) {
85       Traits::CloseHandle(handle_);
86       handle_ = Traits::NullHandle();
87     }
88   }
89 
90  private:
91   FRIEND_TEST_ALL_PREFIXES(ScopedHandleTest, ActiveVerifierWrongOwner);
92   FRIEND_TEST_ALL_PREFIXES(ScopedHandleTest, ActiveVerifierUntrackedHandle);
93   Handle handle_;
94 
95   GenericScopedHandle(const GenericScopedHandle&) = delete;
96   GenericScopedHandle& operator=(const GenericScopedHandle&) = delete;
97 };
98 
99 #undef BASE_WIN_GET_CALLER
100 
101 // The traits class for Win32 handles that can be closed via CloseHandle() API.
102 class HandleTraits {
103  public:
104   typedef HANDLE Handle;
105 
106   // Closes the handle.
107   static bool CloseHandle(HANDLE handle);
108 
109   // Returns true if the handle value is valid.
IsHandleValid(HANDLE handle)110   static bool IsHandleValid(HANDLE handle) {
111     return handle != NULL && handle != INVALID_HANDLE_VALUE;
112   }
113 
114   // Returns NULL handle value.
NullHandle()115   static HANDLE NullHandle() { return NULL; }
116 
117  private:
118   HandleTraits() = delete;
119   HandleTraits(const HandleTraits&) = delete;
120   HandleTraits& operator=(const HandleTraits&) = delete;
121 };
122 
123 // Do-nothing verifier.
124 class DummyVerifierTraits {
125  public:
126   typedef HANDLE Handle;
127 
StartTracking(HANDLE handle,const void * owner,const void * pc1,const void * pc2)128   static void StartTracking(HANDLE handle,
129                             const void* owner,
130                             const void* pc1,
131                             const void* pc2) {}
StopTracking(HANDLE handle,const void * owner,const void * pc1,const void * pc2)132   static void StopTracking(HANDLE handle,
133                            const void* owner,
134                            const void* pc1,
135                            const void* pc2) {}
136 
137  private:
138   DummyVerifierTraits() = delete;
139   DummyVerifierTraits(const DummyVerifierTraits&) = delete;
140   DummyVerifierTraits& operator=(const DummyVerifierTraits&) = delete;
141 };
142 
143 // Performs actual run-time tracking.
144 class VerifierTraits {
145  public:
146   typedef HANDLE Handle;
147 
148   static void StartTracking(HANDLE handle,
149                             const void* owner,
150                             const void* pc1,
151                             const void* pc2);
152   static void StopTracking(HANDLE handle,
153                            const void* owner,
154                            const void* pc1,
155                            const void* pc2);
156 
157  private:
158   VerifierTraits() = delete;
159   VerifierTraits(const VerifierTraits&) = delete;
160   VerifierTraits& operator=(const VerifierTraits&) = delete;
161 };
162 
163 typedef GenericScopedHandle<HandleTraits, VerifierTraits> ScopedHandle;
164 
165 // This function may be called by the embedder to disable the use of
166 // VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used
167 // for ScopedHandle.
168 void DisableHandleVerifier();
169 
170 // This should be called whenever the OS is closing a handle, if extended
171 // verification of improper handle closing is desired. If |handle| is being
172 // tracked by the handle verifier and ScopedHandle is not the one closing it,
173 // a CHECK is generated.
174 void OnHandleBeingClosed(HANDLE handle);
175 }  // namespace win
176 }  // namespace base
177 
178 #endif  // BASE_WIN_SCOPED_HANDLE_H_
179