scoped_handle.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. #ifndef BASE_WIN_SCOPED_HANDLE_H_
  5. #define BASE_WIN_SCOPED_HANDLE_H_
  6. #include "base/win/windows_types.h"
  7. #include "base/base_export.h"
  8. #include "base/check_op.h"
  9. #include "base/compiler_specific.h"
  10. #include "base/dcheck_is_on.h"
  11. #include "base/gtest_prod_util.h"
  12. #include "base/location.h"
  13. #include "base/macros.h"
  14. #include "build/build_config.h"
  15. // TODO(rvargas): remove this with the rest of the verifier.
  16. #if defined(COMPILER_MSVC)
  17. #include <intrin.h>
  18. #define BASE_WIN_GET_CALLER _ReturnAddress()
  19. #elif defined(COMPILER_GCC)
  20. #define BASE_WIN_GET_CALLER \
  21. __builtin_extract_return_addr(__builtin_return_address(0))
  22. #endif
  23. namespace base {
  24. namespace win {
  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. using Handle = typename Traits::Handle;
  38. GenericScopedHandle() : handle_(Traits::NullHandle()) {}
  39. explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
  40. Set(handle);
  41. }
  42. GenericScopedHandle(GenericScopedHandle&& other)
  43. : handle_(Traits::NullHandle()) {
  44. Set(other.Take());
  45. }
  46. ~GenericScopedHandle() { Close(); }
  47. bool IsValid() const { return Traits::IsHandleValid(handle_); }
  48. GenericScopedHandle& operator=(GenericScopedHandle&& other) {
  49. DCHECK_NE(this, &other);
  50. Set(other.Take());
  51. return *this;
  52. }
  53. void Set(Handle handle) {
  54. if (handle_ != handle) {
  55. // Preserve old LastError to avoid bug 528394.
  56. auto last_error = ::GetLastError();
  57. Close();
  58. if (Traits::IsHandleValid(handle)) {
  59. handle_ = handle;
  60. Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
  61. GetProgramCounter());
  62. }
  63. ::SetLastError(last_error);
  64. }
  65. }
  66. Handle Get() const { return handle_; }
  67. // Transfers ownership away from this object.
  68. Handle Take() WARN_UNUSED_RESULT {
  69. Handle temp = handle_;
  70. handle_ = Traits::NullHandle();
  71. if (Traits::IsHandleValid(temp)) {
  72. Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER,
  73. GetProgramCounter());
  74. }
  75. return temp;
  76. }
  77. // Explicitly closes the owned handle.
  78. void Close() {
  79. if (Traits::IsHandleValid(handle_)) {
  80. Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER,
  81. GetProgramCounter());
  82. Traits::CloseHandle(handle_);
  83. handle_ = Traits::NullHandle();
  84. }
  85. }
  86. private:
  87. FRIEND_TEST_ALL_PREFIXES(ScopedHandleTest, HandleVerifierWrongOwner);
  88. FRIEND_TEST_ALL_PREFIXES(ScopedHandleTest, HandleVerifierUntrackedHandle);
  89. Handle handle_;
  90. DISALLOW_COPY_AND_ASSIGN(GenericScopedHandle);
  91. };
  92. #undef BASE_WIN_GET_CALLER
  93. // The traits class for Win32 handles that can be closed via CloseHandle() API.
  94. class HandleTraits {
  95. public:
  96. using Handle = HANDLE;
  97. // Closes the handle.
  98. static bool BASE_EXPORT CloseHandle(HANDLE handle);
  99. // Returns true if the handle value is valid.
  100. static bool IsHandleValid(HANDLE handle) {
  101. return handle != nullptr && handle != INVALID_HANDLE_VALUE;
  102. }
  103. // Returns NULL handle value.
  104. static HANDLE NullHandle() { return nullptr; }
  105. private:
  106. DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits);
  107. };
  108. // Do-nothing verifier.
  109. class DummyVerifierTraits {
  110. public:
  111. using Handle = HANDLE;
  112. static void StartTracking(HANDLE handle,
  113. const void* owner,
  114. const void* pc1,
  115. const void* pc2) {}
  116. static void StopTracking(HANDLE handle,
  117. const void* owner,
  118. const void* pc1,
  119. const void* pc2) {}
  120. private:
  121. DISALLOW_IMPLICIT_CONSTRUCTORS(DummyVerifierTraits);
  122. };
  123. // Performs actual run-time tracking.
  124. class BASE_EXPORT VerifierTraits {
  125. public:
  126. using Handle = HANDLE;
  127. static void StartTracking(HANDLE handle,
  128. const void* owner,
  129. const void* pc1,
  130. const void* pc2);
  131. static void StopTracking(HANDLE handle,
  132. const void* owner,
  133. const void* pc1,
  134. const void* pc2);
  135. private:
  136. DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits);
  137. };
  138. using UncheckedScopedHandle =
  139. GenericScopedHandle<HandleTraits, DummyVerifierTraits>;
  140. using CheckedScopedHandle = GenericScopedHandle<HandleTraits, VerifierTraits>;
  141. #if DCHECK_IS_ON() && !defined(ARCH_CPU_64_BITS)
  142. using ScopedHandle = CheckedScopedHandle;
  143. #else
  144. using ScopedHandle = UncheckedScopedHandle;
  145. #endif
  146. // This function may be called by the embedder to disable the use of
  147. // VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used
  148. // for ScopedHandle.
  149. BASE_EXPORT void DisableHandleVerifier();
  150. // This should be called whenever the OS is closing a handle, if extended
  151. // verification of improper handle closing is desired. If |handle| is being
  152. // tracked by the handle verifier and ScopedHandle is not the one closing it,
  153. // a CHECK is generated.
  154. BASE_EXPORT void OnHandleBeingClosed(HANDLE handle);
  155. } // namespace win
  156. } // namespace base
  157. #endif // BASE_WIN_SCOPED_HANDLE_H_