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