blob: e67e44717fdb15f5d3647b974066bf750754d3fd [file] [log] [blame]
Scott Graham66962112018-06-08 12:42:08 -07001// 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
Scott Graham66962112018-06-08 12:42:08 -070010#include "base/gtest_prod_util.h"
Scott Graham66962112018-06-08 12:42:08 -070011#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)
Scott Graham98cd3ca2018-06-14 22:26:55 -070019#define BASE_WIN_GET_CALLER \
20 __builtin_extract_return_addr(\ __builtin_return_address(0))
Scott Graham66962112018-06-08 12:42:08 -070021#endif
22
23namespace base {
24namespace 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.
35template <class Traits, class Verifier>
36class GenericScopedHandle {
37 public:
38 typedef typename Traits::Handle Handle;
39
40 GenericScopedHandle() : handle_(Traits::NullHandle()) {}
41
42 explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
43 Set(handle);
44 }
45
46 GenericScopedHandle(GenericScopedHandle&& other)
47 : handle_(Traits::NullHandle()) {
48 Set(other.Take());
49 }
50
Scott Graham98cd3ca2018-06-14 22:26:55 -070051 ~GenericScopedHandle() { Close(); }
Scott Graham66962112018-06-08 12:42:08 -070052
Scott Graham98cd3ca2018-06-14 22:26:55 -070053 bool IsValid() const { return Traits::IsHandleValid(handle_); }
Scott Graham66962112018-06-08 12:42:08 -070054
55 GenericScopedHandle& operator=(GenericScopedHandle&& other) {
56 DCHECK_NE(this, &other);
57 Set(other.Take());
58 return *this;
59 }
60
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;
Scott Graham66962112018-06-08 12:42:08 -070069 }
70 ::SetLastError(last_error);
71 }
72 }
73
Scott Graham98cd3ca2018-06-14 22:26:55 -070074 Handle Get() const { return handle_; }
Scott Graham66962112018-06-08 12:42:08 -070075
76 // Transfers ownership away from this object.
77 Handle Take() {
78 Handle temp = handle_;
79 handle_ = Traits::NullHandle();
Scott Graham66962112018-06-08 12:42:08 -070080 return temp;
81 }
82
83 // Explicitly closes the owned handle.
84 void Close() {
85 if (Traits::IsHandleValid(handle_)) {
Scott Graham66962112018-06-08 12:42:08 -070086 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.
102class HandleTraits {
103 public:
104 typedef HANDLE Handle;
105
106 // Closes the handle.
Scott Graham44598072018-06-14 22:01:37 -0700107 static bool CloseHandle(HANDLE handle);
Scott Graham66962112018-06-08 12:42:08 -0700108
109 // Returns true if the handle value is valid.
110 static bool IsHandleValid(HANDLE handle) {
111 return handle != NULL && handle != INVALID_HANDLE_VALUE;
112 }
113
114 // Returns NULL handle value.
Scott Graham98cd3ca2018-06-14 22:26:55 -0700115 static HANDLE NullHandle() { return NULL; }
Scott Graham66962112018-06-08 12:42:08 -0700116
117 private:
118 DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits);
119};
120
121// Do-nothing verifier.
122class DummyVerifierTraits {
123 public:
124 typedef HANDLE Handle;
125
Scott Graham98cd3ca2018-06-14 22:26:55 -0700126 static void StartTracking(HANDLE handle,
127 const void* owner,
128 const void* pc1,
129 const void* pc2) {}
130 static void StopTracking(HANDLE handle,
131 const void* owner,
132 const void* pc1,
133 const void* pc2) {}
Scott Graham66962112018-06-08 12:42:08 -0700134
135 private:
136 DISALLOW_IMPLICIT_CONSTRUCTORS(DummyVerifierTraits);
137};
138
139// Performs actual run-time tracking.
Scott Graham44598072018-06-14 22:01:37 -0700140class VerifierTraits {
Scott Graham66962112018-06-08 12:42:08 -0700141 public:
142 typedef HANDLE Handle;
143
Scott Graham98cd3ca2018-06-14 22:26:55 -0700144 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);
Scott Graham66962112018-06-08 12:42:08 -0700152
153 private:
154 DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits);
155};
156
157typedef 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.
Scott Graham44598072018-06-14 22:01:37 -0700162void DisableHandleVerifier();
Scott Graham66962112018-06-08 12:42:08 -0700163
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.
Scott Graham44598072018-06-14 22:01:37 -0700168void OnHandleBeingClosed(HANDLE handle);
Scott Graham66962112018-06-08 12:42:08 -0700169} // namespace win
170} // namespace base
171
172#endif // BASE_WIN_SCOPED_HANDLE_H_