tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

scoped_handle.h (6765B)


      1 // Copyright 2012 The Chromium Authors
      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 <ostream>
      9 
     10 #include "base/base_export.h"
     11 #include "base/check_op.h"
     12 #include "base/dcheck_is_on.h"
     13 #include "base/gtest_prod_util.h"
     14 #include "base/location.h"
     15 #include "base/win/windows_types.h"
     16 #include "build/build_config.h"
     17 
     18 // TODO(rvargas): remove this with the rest of the verifier.
     19 #if defined(COMPILER_MSVC)
     20 #include <intrin.h>
     21 #define BASE_WIN_GET_CALLER _ReturnAddress()
     22 #elif defined(COMPILER_GCC)
     23 #define BASE_WIN_GET_CALLER \
     24  __builtin_extract_return_addr(__builtin_return_address(0))
     25 #endif
     26 
     27 namespace base {
     28 namespace win {
     29 
     30 enum class HandleOperation {
     31  kHandleAlreadyTracked,
     32  kCloseHandleNotTracked,
     33  kCloseHandleNotOwner,
     34  kCloseHandleHook,
     35  kDuplicateHandleHook
     36 };
     37 
     38 std::ostream& operator<<(std::ostream& os, HandleOperation operation);
     39 
     40 // Generic wrapper for raw handles that takes care of closing handles
     41 // automatically. The class interface follows the style of
     42 // the ScopedFILE class with two additions:
     43 //   - IsValid() method can tolerate multiple invalid handle values such as NULL
     44 //     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
     45 //   - Set() (and the constructors and assignment operators that call it)
     46 //     preserve the Windows LastError code. This ensures that GetLastError() can
     47 //     be called after stashing a handle in a GenericScopedHandle object. Doing
     48 //     this explicitly is necessary because of bug 528394 and VC++ 2015.
     49 template <class Traits, class Verifier>
     50 class GenericScopedHandle {
     51 public:
     52  using Handle = typename Traits::Handle;
     53 
     54  GenericScopedHandle() : handle_(Traits::NullHandle()) {}
     55 
     56  explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
     57    Set(handle);
     58  }
     59 
     60  GenericScopedHandle(GenericScopedHandle&& other)
     61      : handle_(Traits::NullHandle()) {
     62    Set(other.Take());
     63  }
     64 
     65  GenericScopedHandle(const GenericScopedHandle&) = delete;
     66  GenericScopedHandle& operator=(const GenericScopedHandle&) = delete;
     67 
     68  ~GenericScopedHandle() { Close(); }
     69 
     70  bool is_valid() const { return Traits::IsHandleValid(handle_); }
     71 
     72  // TODO(crbug.com/1291793): Migrate callers to is_valid().
     73  bool IsValid() const { return is_valid(); }
     74 
     75  GenericScopedHandle& operator=(GenericScopedHandle&& other) {
     76    DCHECK_NE(this, &other);
     77    Set(other.Take());
     78    return *this;
     79  }
     80 
     81  void Set(Handle handle) {
     82    if (handle_ != handle) {
     83      // Preserve old LastError to avoid bug 528394.
     84      auto last_error = ::GetLastError();
     85      Close();
     86 
     87      if (Traits::IsHandleValid(handle)) {
     88        handle_ = handle;
     89        Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
     90                                GetProgramCounter());
     91      }
     92      ::SetLastError(last_error);
     93    }
     94  }
     95 
     96  Handle get() const { return handle_; }
     97 
     98  // TODO(crbug.com/1291793): Migrate callers to get().
     99  Handle Get() const { return get(); }
    100 
    101  // Transfers ownership away from this object.
    102  [[nodiscard]] Handle release() {
    103    Handle temp = handle_;
    104    handle_ = Traits::NullHandle();
    105    if (Traits::IsHandleValid(temp)) {
    106      Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER,
    107                             GetProgramCounter());
    108    }
    109    return temp;
    110  }
    111 
    112  // TODO(crbug.com/1291793): Migrate callers to release().
    113  [[nodiscard]] Handle Take() { return release(); }
    114 
    115  // Explicitly closes the owned handle.
    116  void Close() {
    117    if (Traits::IsHandleValid(handle_)) {
    118      Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER,
    119                             GetProgramCounter());
    120 
    121      Traits::CloseHandle(handle_);
    122      handle_ = Traits::NullHandle();
    123    }
    124  }
    125 
    126 private:
    127  FRIEND_TEST_ALL_PREFIXES(ScopedHandleDeathTest, HandleVerifierWrongOwner);
    128  FRIEND_TEST_ALL_PREFIXES(ScopedHandleDeathTest,
    129                           HandleVerifierUntrackedHandle);
    130  Handle handle_;
    131 };
    132 
    133 #undef BASE_WIN_GET_CALLER
    134 
    135 // The traits class for Win32 handles that can be closed via CloseHandle() API.
    136 class HandleTraits {
    137 public:
    138  using Handle = HANDLE;
    139 
    140  HandleTraits() = delete;
    141  HandleTraits(const HandleTraits&) = delete;
    142  HandleTraits& operator=(const HandleTraits&) = delete;
    143 
    144  // Closes the handle.
    145  static bool BASE_EXPORT CloseHandle(HANDLE handle);
    146 
    147  // Returns true if the handle value is valid.
    148  static bool IsHandleValid(HANDLE handle) {
    149    return handle != nullptr && handle != INVALID_HANDLE_VALUE;
    150  }
    151 
    152  // Returns NULL handle value.
    153  static HANDLE NullHandle() { return nullptr; }
    154 };
    155 
    156 // Do-nothing verifier.
    157 class DummyVerifierTraits {
    158 public:
    159  using Handle = HANDLE;
    160 
    161  DummyVerifierTraits() = delete;
    162  DummyVerifierTraits(const DummyVerifierTraits&) = delete;
    163  DummyVerifierTraits& operator=(const DummyVerifierTraits&) = delete;
    164 
    165  static void StartTracking(HANDLE handle,
    166                            const void* owner,
    167                            const void* pc1,
    168                            const void* pc2) {}
    169  static void StopTracking(HANDLE handle,
    170                           const void* owner,
    171                           const void* pc1,
    172                           const void* pc2) {}
    173 };
    174 
    175 // Performs actual run-time tracking.
    176 class BASE_EXPORT VerifierTraits {
    177 public:
    178  using Handle = HANDLE;
    179 
    180  VerifierTraits() = delete;
    181  VerifierTraits(const VerifierTraits&) = delete;
    182  VerifierTraits& operator=(const VerifierTraits&) = delete;
    183 
    184  static void StartTracking(HANDLE handle,
    185                            const void* owner,
    186                            const void* pc1,
    187                            const void* pc2);
    188  static void StopTracking(HANDLE handle,
    189                           const void* owner,
    190                           const void* pc1,
    191                           const void* pc2);
    192 };
    193 
    194 using UncheckedScopedHandle =
    195    GenericScopedHandle<HandleTraits, DummyVerifierTraits>;
    196 using CheckedScopedHandle = GenericScopedHandle<HandleTraits, VerifierTraits>;
    197 
    198 #if DCHECK_IS_ON()
    199 using ScopedHandle = CheckedScopedHandle;
    200 #else
    201 using ScopedHandle = UncheckedScopedHandle;
    202 #endif
    203 
    204 // This function may be called by the embedder to disable the use of
    205 // VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used
    206 // for ScopedHandle.
    207 BASE_EXPORT void DisableHandleVerifier();
    208 
    209 // This should be called whenever the OS is closing a handle, if extended
    210 // verification of improper handle closing is desired. If |handle| is being
    211 // tracked by the handle verifier and ScopedHandle is not the one closing it,
    212 // a CHECK is generated.
    213 BASE_EXPORT void OnHandleBeingClosed(HANDLE handle, HandleOperation operation);
    214 
    215 }  // namespace win
    216 }  // namespace base
    217 
    218 #endif  // BASE_WIN_SCOPED_HANDLE_H_