tor-browser

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

DynamicallyLinkedFunctionPtr.h (4185B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_DynamicallyLinkedFunctionPtr_h
      8 #define mozilla_DynamicallyLinkedFunctionPtr_h
      9 
     10 #include <windows.h>
     11 
     12 #include <utility>
     13 
     14 #include "mozilla/Attributes.h"
     15 
     16 namespace mozilla {
     17 namespace detail {
     18 
     19 template <typename T>
     20 struct FunctionPtrCracker;
     21 
     22 template <typename R, typename... Args>
     23 struct FunctionPtrCracker<R (*)(Args...)> {
     24  using ReturnT = R;
     25  using FunctionPtrT = R (*)(Args...);
     26 };
     27 
     28 #if defined(_M_IX86)
     29 template <typename R, typename... Args>
     30 struct FunctionPtrCracker<R(__stdcall*)(Args...)> {
     31  using ReturnT = R;
     32  using FunctionPtrT = R(__stdcall*)(Args...);
     33 };
     34 
     35 template <typename R, typename... Args>
     36 struct FunctionPtrCracker<R(__fastcall*)(Args...)> {
     37  using ReturnT = R;
     38  using FunctionPtrT = R(__fastcall*)(Args...);
     39 };
     40 #endif  // defined(_M_IX86)
     41 
     42 template <typename T>
     43 class DynamicallyLinkedFunctionPtrBase {
     44 public:
     45  using ReturnT = typename FunctionPtrCracker<T>::ReturnT;
     46  using FunctionPtrT = typename FunctionPtrCracker<T>::FunctionPtrT;
     47 
     48  DynamicallyLinkedFunctionPtrBase(const wchar_t* aLibName,
     49                                   const char* aFuncName)
     50      : mModule(::LoadLibraryW(aLibName)), mFunction(nullptr) {
     51    if (!mModule) {
     52      return;
     53    }
     54 
     55    mFunction =
     56        reinterpret_cast<FunctionPtrT>(::GetProcAddress(mModule, aFuncName));
     57 
     58    if (!mFunction) {
     59      // Since the function doesn't exist, there is no point in holding a
     60      // reference to mModule anymore.
     61      ::FreeLibrary(mModule);
     62      mModule = nullptr;
     63    }
     64  }
     65 
     66  DynamicallyLinkedFunctionPtrBase(const DynamicallyLinkedFunctionPtrBase&) =
     67      delete;
     68  DynamicallyLinkedFunctionPtrBase& operator=(
     69      const DynamicallyLinkedFunctionPtrBase&) = delete;
     70 
     71  DynamicallyLinkedFunctionPtrBase(DynamicallyLinkedFunctionPtrBase&&) = delete;
     72  DynamicallyLinkedFunctionPtrBase& operator=(
     73      DynamicallyLinkedFunctionPtrBase&&) = delete;
     74 
     75  template <typename... Args>
     76  ReturnT operator()(Args&&... args) const {
     77    return mFunction(std::forward<Args>(args)...);
     78  }
     79 
     80  explicit operator bool() const { return !!mFunction; }
     81 
     82 protected:
     83  HMODULE mModule;
     84  FunctionPtrT mFunction;
     85 };
     86 
     87 }  // namespace detail
     88 
     89 /**
     90 * In most cases, this class is the one that you want to use for resolving a
     91 * dynamically-linked function pointer. It should be instantiated as a static
     92 * local variable.
     93 *
     94 * NB: It has a trivial destructor, so the DLL that is loaded is never freed.
     95 * Assuming that this function is called fairly often, this is the most
     96 * sensible option. OTOH, if the function you are calling is a one-off, or the
     97 * static local requirement is too restrictive, use DynamicallyLinkedFunctionPtr
     98 * instead.
     99 */
    100 template <typename T>
    101 class MOZ_STATIC_LOCAL_CLASS StaticDynamicallyLinkedFunctionPtr final
    102    : public detail::DynamicallyLinkedFunctionPtrBase<T> {
    103 public:
    104  StaticDynamicallyLinkedFunctionPtr(const wchar_t* aLibName,
    105                                     const char* aFuncName)
    106      : detail::DynamicallyLinkedFunctionPtrBase<T>(aLibName, aFuncName) {}
    107 
    108  /**
    109   * We only offer this operator for the static local case, as it is not
    110   * possible for this object to be destroyed while the returned pointer is
    111   * being held.
    112   */
    113  operator typename detail::DynamicallyLinkedFunctionPtrBase<T>::FunctionPtrT()
    114      const {
    115    return this->mFunction;
    116  }
    117 };
    118 
    119 template <typename T>
    120 class MOZ_NON_PARAM MOZ_NON_TEMPORARY_CLASS DynamicallyLinkedFunctionPtr final
    121    : public detail::DynamicallyLinkedFunctionPtrBase<T> {
    122 public:
    123  DynamicallyLinkedFunctionPtr(const wchar_t* aLibName, const char* aFuncName)
    124      : detail::DynamicallyLinkedFunctionPtrBase<T>(aLibName, aFuncName) {}
    125 
    126  ~DynamicallyLinkedFunctionPtr() {
    127    if (!this->mModule) {
    128      return;
    129    }
    130 
    131    ::FreeLibrary(this->mModule);
    132  }
    133 };
    134 
    135 }  // namespace mozilla
    136 
    137 #endif  // mozilla_DynamicallyLinkedFunctionPtr_h