16d528ed9Sopenharmony_ci// Copyright (c) 2012 The Chromium Authors. All rights reserved.
26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
36d528ed9Sopenharmony_ci// found in the LICENSE file.
46d528ed9Sopenharmony_ci
56d528ed9Sopenharmony_ci#ifndef BASE_WIN_SCOPED_HANDLE_H_
66d528ed9Sopenharmony_ci#define BASE_WIN_SCOPED_HANDLE_H_
76d528ed9Sopenharmony_ci
86d528ed9Sopenharmony_ci#include <windows.h>
96d528ed9Sopenharmony_ci
106d528ed9Sopenharmony_ci#include "base/gtest_prod_util.h"
116d528ed9Sopenharmony_ci#include "base/logging.h"
126d528ed9Sopenharmony_ci
136d528ed9Sopenharmony_ci// TODO(rvargas): remove this with the rest of the verifier.
146d528ed9Sopenharmony_ci#if defined(COMPILER_MSVC)
156d528ed9Sopenharmony_ci#include <intrin.h>
166d528ed9Sopenharmony_ci#define BASE_WIN_GET_CALLER _ReturnAddress()
176d528ed9Sopenharmony_ci#elif defined(COMPILER_GCC)
186d528ed9Sopenharmony_ci#define BASE_WIN_GET_CALLER \
196d528ed9Sopenharmony_ci  __builtin_extract_return_addr(\ __builtin_return_address(0))
206d528ed9Sopenharmony_ci#endif
216d528ed9Sopenharmony_ci
226d528ed9Sopenharmony_cinamespace base {
236d528ed9Sopenharmony_cinamespace win {
246d528ed9Sopenharmony_ci
256d528ed9Sopenharmony_ci// Generic wrapper for raw handles that takes care of closing handles
266d528ed9Sopenharmony_ci// automatically. The class interface follows the style of
276d528ed9Sopenharmony_ci// the ScopedFILE class with two additions:
286d528ed9Sopenharmony_ci//   - IsValid() method can tolerate multiple invalid handle values such as NULL
296d528ed9Sopenharmony_ci//     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
306d528ed9Sopenharmony_ci//   - Set() (and the constructors and assignment operators that call it)
316d528ed9Sopenharmony_ci//     preserve the Windows LastError code. This ensures that GetLastError() can
326d528ed9Sopenharmony_ci//     be called after stashing a handle in a GenericScopedHandle object. Doing
336d528ed9Sopenharmony_ci//     this explicitly is necessary because of bug 528394 and VC++ 2015.
346d528ed9Sopenharmony_citemplate <class Traits, class Verifier>
356d528ed9Sopenharmony_ciclass GenericScopedHandle {
366d528ed9Sopenharmony_ci public:
376d528ed9Sopenharmony_ci  typedef typename Traits::Handle Handle;
386d528ed9Sopenharmony_ci
396d528ed9Sopenharmony_ci  GenericScopedHandle() : handle_(Traits::NullHandle()) {}
406d528ed9Sopenharmony_ci
416d528ed9Sopenharmony_ci  explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
426d528ed9Sopenharmony_ci    Set(handle);
436d528ed9Sopenharmony_ci  }
446d528ed9Sopenharmony_ci
456d528ed9Sopenharmony_ci  GenericScopedHandle(GenericScopedHandle&& other)
466d528ed9Sopenharmony_ci      : handle_(Traits::NullHandle()) {
476d528ed9Sopenharmony_ci    Set(other.Take());
486d528ed9Sopenharmony_ci  }
496d528ed9Sopenharmony_ci
506d528ed9Sopenharmony_ci  ~GenericScopedHandle() { Close(); }
516d528ed9Sopenharmony_ci
526d528ed9Sopenharmony_ci  bool IsValid() const { return Traits::IsHandleValid(handle_); }
536d528ed9Sopenharmony_ci
546d528ed9Sopenharmony_ci  GenericScopedHandle& operator=(GenericScopedHandle&& other) {
556d528ed9Sopenharmony_ci    DCHECK_NE(this, &other);
566d528ed9Sopenharmony_ci    Set(other.Take());
576d528ed9Sopenharmony_ci    return *this;
586d528ed9Sopenharmony_ci  }
596d528ed9Sopenharmony_ci
606d528ed9Sopenharmony_ci  void Set(Handle handle) {
616d528ed9Sopenharmony_ci    if (handle_ != handle) {
626d528ed9Sopenharmony_ci      // Preserve old LastError to avoid bug 528394.
636d528ed9Sopenharmony_ci      auto last_error = ::GetLastError();
646d528ed9Sopenharmony_ci      Close();
656d528ed9Sopenharmony_ci
666d528ed9Sopenharmony_ci      if (Traits::IsHandleValid(handle)) {
676d528ed9Sopenharmony_ci        handle_ = handle;
686d528ed9Sopenharmony_ci      }
696d528ed9Sopenharmony_ci      ::SetLastError(last_error);
706d528ed9Sopenharmony_ci    }
716d528ed9Sopenharmony_ci  }
726d528ed9Sopenharmony_ci
736d528ed9Sopenharmony_ci  Handle Get() const { return handle_; }
746d528ed9Sopenharmony_ci
756d528ed9Sopenharmony_ci  // Transfers ownership away from this object.
766d528ed9Sopenharmony_ci  Handle Take() {
776d528ed9Sopenharmony_ci    Handle temp = handle_;
786d528ed9Sopenharmony_ci    handle_ = Traits::NullHandle();
796d528ed9Sopenharmony_ci    return temp;
806d528ed9Sopenharmony_ci  }
816d528ed9Sopenharmony_ci
826d528ed9Sopenharmony_ci  // Explicitly closes the owned handle.
836d528ed9Sopenharmony_ci  void Close() {
846d528ed9Sopenharmony_ci    if (Traits::IsHandleValid(handle_)) {
856d528ed9Sopenharmony_ci      Traits::CloseHandle(handle_);
866d528ed9Sopenharmony_ci      handle_ = Traits::NullHandle();
876d528ed9Sopenharmony_ci    }
886d528ed9Sopenharmony_ci  }
896d528ed9Sopenharmony_ci
906d528ed9Sopenharmony_ci private:
916d528ed9Sopenharmony_ci  FRIEND_TEST_ALL_PREFIXES(ScopedHandleTest, ActiveVerifierWrongOwner);
926d528ed9Sopenharmony_ci  FRIEND_TEST_ALL_PREFIXES(ScopedHandleTest, ActiveVerifierUntrackedHandle);
936d528ed9Sopenharmony_ci  Handle handle_;
946d528ed9Sopenharmony_ci
956d528ed9Sopenharmony_ci  GenericScopedHandle(const GenericScopedHandle&) = delete;
966d528ed9Sopenharmony_ci  GenericScopedHandle& operator=(const GenericScopedHandle&) = delete;
976d528ed9Sopenharmony_ci};
986d528ed9Sopenharmony_ci
996d528ed9Sopenharmony_ci#undef BASE_WIN_GET_CALLER
1006d528ed9Sopenharmony_ci
1016d528ed9Sopenharmony_ci// The traits class for Win32 handles that can be closed via CloseHandle() API.
1026d528ed9Sopenharmony_ciclass HandleTraits {
1036d528ed9Sopenharmony_ci public:
1046d528ed9Sopenharmony_ci  typedef HANDLE Handle;
1056d528ed9Sopenharmony_ci
1066d528ed9Sopenharmony_ci  // Closes the handle.
1076d528ed9Sopenharmony_ci  static bool CloseHandle(HANDLE handle);
1086d528ed9Sopenharmony_ci
1096d528ed9Sopenharmony_ci  // Returns true if the handle value is valid.
1106d528ed9Sopenharmony_ci  static bool IsHandleValid(HANDLE handle) {
1116d528ed9Sopenharmony_ci    return handle != NULL && handle != INVALID_HANDLE_VALUE;
1126d528ed9Sopenharmony_ci  }
1136d528ed9Sopenharmony_ci
1146d528ed9Sopenharmony_ci  // Returns NULL handle value.
1156d528ed9Sopenharmony_ci  static HANDLE NullHandle() { return NULL; }
1166d528ed9Sopenharmony_ci
1176d528ed9Sopenharmony_ci private:
1186d528ed9Sopenharmony_ci  HandleTraits() = delete;
1196d528ed9Sopenharmony_ci  HandleTraits(const HandleTraits&) = delete;
1206d528ed9Sopenharmony_ci  HandleTraits& operator=(const HandleTraits&) = delete;
1216d528ed9Sopenharmony_ci};
1226d528ed9Sopenharmony_ci
1236d528ed9Sopenharmony_ci// Do-nothing verifier.
1246d528ed9Sopenharmony_ciclass DummyVerifierTraits {
1256d528ed9Sopenharmony_ci public:
1266d528ed9Sopenharmony_ci  typedef HANDLE Handle;
1276d528ed9Sopenharmony_ci
1286d528ed9Sopenharmony_ci  static void StartTracking(HANDLE handle,
1296d528ed9Sopenharmony_ci                            const void* owner,
1306d528ed9Sopenharmony_ci                            const void* pc1,
1316d528ed9Sopenharmony_ci                            const void* pc2) {}
1326d528ed9Sopenharmony_ci  static void StopTracking(HANDLE handle,
1336d528ed9Sopenharmony_ci                           const void* owner,
1346d528ed9Sopenharmony_ci                           const void* pc1,
1356d528ed9Sopenharmony_ci                           const void* pc2) {}
1366d528ed9Sopenharmony_ci
1376d528ed9Sopenharmony_ci private:
1386d528ed9Sopenharmony_ci  DummyVerifierTraits() = delete;
1396d528ed9Sopenharmony_ci  DummyVerifierTraits(const DummyVerifierTraits&) = delete;
1406d528ed9Sopenharmony_ci  DummyVerifierTraits& operator=(const DummyVerifierTraits&) = delete;
1416d528ed9Sopenharmony_ci};
1426d528ed9Sopenharmony_ci
1436d528ed9Sopenharmony_ci// Performs actual run-time tracking.
1446d528ed9Sopenharmony_ciclass VerifierTraits {
1456d528ed9Sopenharmony_ci public:
1466d528ed9Sopenharmony_ci  typedef HANDLE Handle;
1476d528ed9Sopenharmony_ci
1486d528ed9Sopenharmony_ci  static void StartTracking(HANDLE handle,
1496d528ed9Sopenharmony_ci                            const void* owner,
1506d528ed9Sopenharmony_ci                            const void* pc1,
1516d528ed9Sopenharmony_ci                            const void* pc2);
1526d528ed9Sopenharmony_ci  static void StopTracking(HANDLE handle,
1536d528ed9Sopenharmony_ci                           const void* owner,
1546d528ed9Sopenharmony_ci                           const void* pc1,
1556d528ed9Sopenharmony_ci                           const void* pc2);
1566d528ed9Sopenharmony_ci
1576d528ed9Sopenharmony_ci private:
1586d528ed9Sopenharmony_ci  VerifierTraits() = delete;
1596d528ed9Sopenharmony_ci  VerifierTraits(const VerifierTraits&) = delete;
1606d528ed9Sopenharmony_ci  VerifierTraits& operator=(const VerifierTraits&) = delete;
1616d528ed9Sopenharmony_ci};
1626d528ed9Sopenharmony_ci
1636d528ed9Sopenharmony_citypedef GenericScopedHandle<HandleTraits, VerifierTraits> ScopedHandle;
1646d528ed9Sopenharmony_ci
1656d528ed9Sopenharmony_ci// This function may be called by the embedder to disable the use of
1666d528ed9Sopenharmony_ci// VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used
1676d528ed9Sopenharmony_ci// for ScopedHandle.
1686d528ed9Sopenharmony_civoid DisableHandleVerifier();
1696d528ed9Sopenharmony_ci
1706d528ed9Sopenharmony_ci// This should be called whenever the OS is closing a handle, if extended
1716d528ed9Sopenharmony_ci// verification of improper handle closing is desired. If |handle| is being
1726d528ed9Sopenharmony_ci// tracked by the handle verifier and ScopedHandle is not the one closing it,
1736d528ed9Sopenharmony_ci// a CHECK is generated.
1746d528ed9Sopenharmony_civoid OnHandleBeingClosed(HANDLE handle);
1756d528ed9Sopenharmony_ci}  // namespace win
1766d528ed9Sopenharmony_ci}  // namespace base
1776d528ed9Sopenharmony_ci
1786d528ed9Sopenharmony_ci#endif  // BASE_WIN_SCOPED_HANDLE_H_
179