Global Metrics

path: .metrics.nom.total
old: 7.0
new: 70.0

path: .metrics.nom.functions
old: 7.0
new: 70.0

path: .metrics.mi.mi_sei
old: -43.631138310451846
new: -63.905615257317294

path: .metrics.mi.mi_original
old: -7.687803775049673
new: -16.6284829577058

path: .metrics.halstead.level
old: 0.007418832119638429
new: 0.0184981684981685

path: .metrics.halstead.estimated_program_length
old: 3429.5188677682713
new: 2703.812403527932

path: .metrics.halstead.purity_ratio
old: 0.5078511576733705
new: 1.2245527189890997

path: .metrics.halstead.n2
old: 380.0
new: 303.0

path: .metrics.halstead.n1
old: 34.0
new: 39.0

path: .metrics.halstead.effort
old: 7913255.951511428
new: 1004781.5466005903

path: .metrics.halstead.time
old: 439625.33063952375
new: 55821.19703336613

path: .metrics.halstead.bugs
old: 13.236776033564936
new: 3.343950542543645

path: .metrics.halstead.vocabulary
old: 414.0
new: 342.0

path: .metrics.halstead.volume
old: 58707.11742399294
new: 18586.618352868063

path: .metrics.halstead.N1
old: 3740.0
new: 1368.0

path: .metrics.halstead.difficulty
old: 134.7921052631579
new: 54.05940594059406

path: .metrics.halstead.length
old: 6753.0
new: 2208.0

path: .metrics.halstead.N2
old: 3013.0
new: 840.0

path: .metrics.nargs.sum
old: 10.0
new: 49.0

path: .metrics.nargs.average
old: 1.4285714285714286
new: 0.7

path: .metrics.nexits.sum
old: 9.0
new: 73.0

path: .metrics.nexits.average
old: 1.2857142857142858
new: 1.042857142857143

path: .metrics.loc.lloc
old: 170.0
new: 144.0

path: .metrics.loc.cloc
old: 235.0
new: 69.0

path: .metrics.loc.ploc
old: 577.0
new: 521.0

path: .metrics.loc.sloc
old: 798.0
new: 742.0

path: .metrics.loc.blank
old: 0.0
new: 152.0

path: .metrics.cognitive.sum
old: 72.0
new: 47.0

path: .metrics.cognitive.average
old: 10.285714285714286
new: 0.6714285714285714

path: .metrics.cyclomatic.sum
old: 58.0
new: 128.0

path: .metrics.cyclomatic.average
old: 5.2727272727272725
new: 1.5609756097560976

Spaces Data

Minimal test - lines (71, 740)

path: .spaces[1].metrics.cyclomatic.average
old: 12.0
new: 1.575

path: .spaces[1].metrics.cyclomatic.sum
old: 12.0
new: 126.0

path: .spaces[1].metrics.halstead.difficulty
old: 19.86111111111111
new: 55.74381625441696

path: .spaces[1].metrics.halstead.effort
old: 11512.3136762615
new: 1004490.9266174488

path: .spaces[1].metrics.halstead.N1
old: 62.0
new: 1354.0

path: .spaces[1].metrics.halstead.purity_ratio
old: 1.0526868919811607
new: 1.1609195419588767

path: .spaces[1].metrics.halstead.vocabulary
old: 31.0
new: 322.0

path: .spaces[1].metrics.halstead.N2
old: 55.0
new: 809.0

path: .spaces[1].metrics.halstead.bugs
old: 0.16994973360299917
new: 3.34330571534562

path: .spaces[1].metrics.halstead.estimated_program_length
old: 123.1643663617958
new: 2511.0689692570504

path: .spaces[1].metrics.halstead.n2
old: 18.0
new: 283.0

path: .spaces[1].metrics.halstead.volume
old: 579.6409683152643
new: 18019.77320736192

path: .spaces[1].metrics.halstead.time
old: 639.5729820145277
new: 55805.05147874715

path: .spaces[1].metrics.halstead.length
old: 117.0
new: 2163.0

path: .spaces[1].metrics.halstead.level
old: 0.05034965034965035
new: 0.01793920953377072

path: .spaces[1].metrics.halstead.n1
old: 13.0
new: 39.0

path: .spaces[1].metrics.mi.mi_visual_studio
old: 51.14360368453085
new: 0.0

path: .spaces[1].metrics.mi.mi_sei
old: 51.69269234999679
new: -63.239551480398944

path: .spaces[1].metrics.mi.mi_original
old: 87.45556230054775
new: -14.353868657113082

path: .spaces[1].metrics.cognitive.average
old: 3.0
new: 0.6714285714285714

path: .spaces[1].metrics.cognitive.sum
old: 3.0
new: 47.0

path: .spaces[1].metrics.nom.functions
old: 1.0
new: 70.0

path: .spaces[1].metrics.nom.total
old: 1.0
new: 70.0

path: .spaces[1].metrics.loc.sloc
old: 19.0
new: 670.0

path: .spaces[1].metrics.loc.blank
old: 0.0
new: 138.0

path: .spaces[1].metrics.loc.cloc
old: 0.0
new: 49.0

path: .spaces[1].metrics.loc.ploc
old: 19.0
new: 483.0

path: .spaces[1].metrics.loc.lloc
old: 3.0
new: 144.0

path: .spaces[1].metrics.nexits.sum
old: 2.0
new: 73.0

path: .spaces[1].metrics.nexits.average
old: 2.0
new: 1.042857142857143

path: .spaces[1].metrics.nargs.average
old: 2.0
new: 0.7

path: .spaces[1].metrics.nargs.sum
old: 2.0
new: 49.0

Code

namespace mozilla {

class WindowsError final {
 private:
  // HRESULT and NTSTATUS are both typedefs of LONG, so we cannot use
  // overloading to properly differentiate between the two. Instead we'll use
  // static functions to convert the various error types to HRESULTs before
  // instantiating.
  explicit constexpr WindowsError(HRESULT aHResult) : mHResult(aHResult) {}

 public:
  using UniqueString = UniquePtr;

  static constexpr WindowsError FromNtStatus(NTSTATUS aNtStatus) {
    if (aNtStatus == STATUS_SUCCESS) {
      // Special case: we don't want to set FACILITY_NT_BIT
      // (HRESULT_FROM_NT does not handle this case, unlike HRESULT_FROM_WIN32)
      return WindowsError(S_OK);
    }

    return WindowsError(HRESULT_FROM_NT(aNtStatus));
  }

  static constexpr WindowsError FromHResult(HRESULT aHResult) {
    return WindowsError(aHResult);
  }

  static constexpr WindowsError FromWin32Error(DWORD aWin32Err) {
    return WindowsError(HRESULT_FROM_WIN32(aWin32Err));
  }

  static WindowsError FromLastError() {
    return FromWin32Error(::GetLastError());
  }

  static WindowsError CreateSuccess() { return WindowsError(S_OK); }

  static WindowsError CreateGeneric() {
    return FromWin32Error(ERROR_UNIDENTIFIED_ERROR);
  }

  bool IsSuccess() const { return SUCCEEDED(mHResult); }

  bool IsFailure() const { return FAILED(mHResult); }

  bool IsAvailableAsWin32Error() const {
    return IsAvailableAsNtStatus() ||
           HRESULT_FACILITY(mHResult) == FACILITY_WIN32;
  }

  bool IsAvailableAsNtStatus() const {
    return mHResult == S_OK || (mHResult & FACILITY_NT_BIT);
  }

  bool IsAvailableAsHResult() const { return true; }

  UniqueString AsString() const {
    LPWSTR rawMsgBuf = nullptr;
    constexpr DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
                            FORMAT_MESSAGE_FROM_SYSTEM |
                            FORMAT_MESSAGE_IGNORE_INSERTS;
    DWORD result =
        ::FormatMessageW(flags, nullptr, mHResult, 0,
                         reinterpret_cast(&rawMsgBuf), 0, nullptr);
    if (!result) {
      return nullptr;
    }

    return UniqueString(rawMsgBuf);
  }

  HRESULT AsHResult() const { return mHResult; }

  // Not all HRESULTs are convertible to Win32 Errors, so we use Maybe
  Maybe AsWin32Error() const {
    if (mHResult == S_OK) {
      return Some(static_cast(ERROR_SUCCESS));
    }

    if (HRESULT_FACILITY(mHResult) == FACILITY_WIN32) {
      // This is the inverse of HRESULT_FROM_WIN32
      return Some(static_cast(HRESULT_CODE(mHResult)));
    }

    // The NTSTATUS facility is a special case and thus does not utilize the
    // HRESULT_FACILITY and HRESULT_CODE macros.
    if (mHResult & FACILITY_NT_BIT) {
      return Some(NtStatusToWin32Error(
          static_cast(mHResult & ~FACILITY_NT_BIT)));
    }

    return Nothing();
  }

  // Not all HRESULTs are convertible to NTSTATUS, so we use Maybe
  Maybe AsNtStatus() const {
    if (mHResult == S_OK) {
      return Some(STATUS_SUCCESS);
    }

    // The NTSTATUS facility is a special case and thus does not utilize the
    // HRESULT_FACILITY and HRESULT_CODE macros.
    if (mHResult & FACILITY_NT_BIT) {
      return Some(static_cast(mHResult & ~FACILITY_NT_BIT));
    }

    return Nothing();
  }

  constexpr bool operator==(const WindowsError& aOther) const {
    return mHResult == aOther.mHResult;
  }

  constexpr bool operator!=(const WindowsError& aOther) const {
    return mHResult != aOther.mHResult;
  }

  static DWORD NtStatusToWin32Error(NTSTATUS aNtStatus) {
    static const StaticDynamicallyLinkedFunctionPtr
        pRtlNtStatusToDosError(L"ntdll.dll", "RtlNtStatusToDosError");

    MOZ_ASSERT(!!pRtlNtStatusToDosError);
    if (!pRtlNtStatusToDosError) {
      return ERROR_UNIDENTIFIED_ERROR;
    }

    return pRtlNtStatusToDosError(aNtStatus);
  }

 private:
  // We store the error code as an HRESULT because they can encode both Win32
  // error codes and NTSTATUS codes.
  HRESULT mHResult;
};

namespace detail {
template <>
struct UnusedZero {
  using StorageType = WindowsError;

  static constexpr bool value = true;
  static constexpr StorageType nullValue = WindowsError::FromHResult(S_OK);

  static constexpr void AssertValid(StorageType aValue) {}
  static constexpr const WindowsError& Inspect(const StorageType& aValue) {
    return aValue;
  }
  static constexpr WindowsError Unwrap(StorageType aValue) { return aValue; }
  static constexpr StorageType Store(WindowsError aValue) { return aValue; }
};
}  // namespace detail

enum DetourResultCode : uint32_t {
  RESULT_OK = 0,
  INTERCEPTOR_MOD_NULL,
  INTERCEPTOR_MOD_INACCESSIBLE,
  INTERCEPTOR_PROC_NULL,
  INTERCEPTOR_PROC_INACCESSIBLE,
  DETOUR_PATCHER_RESERVE_FOR_MODULE_PE_ERROR,
  DETOUR_PATCHER_RESERVE_FOR_MODULE_TEXT_ERROR,
  DETOUR_PATCHER_RESERVE_FOR_MODULE_RESERVE_ERROR,
  DETOUR_PATCHER_DO_RESERVE_ERROR,
  DETOUR_PATCHER_NEXT_TRAMPOLINE_ERROR,
  DETOUR_PATCHER_INVALID_TRAMPOLINE,
  DETOUR_PATCHER_WRITE_POINTER_ERROR,
  DETOUR_PATCHER_CREATE_TRAMPOLINE_ERROR,
  FUNCHOOKCROSSPROCESS_COPYSTUB_ERROR,
  MMPOLICY_RESERVE_INVALIDARG,
  MMPOLICY_RESERVE_ZERO_RESERVATIONSIZE,
  MMPOLICY_RESERVE_CREATEFILEMAPPING,
  MMPOLICY_RESERVE_MAPVIEWOFFILE,
  MMPOLICY_RESERVE_NOBOUND_RESERVE_ERROR,
  MMPOLICY_RESERVE_FINDREGION_INVALIDLEN,
  MMPOLICY_RESERVE_FINDREGION_INVALIDRANGE,
  MMPOLICY_RESERVE_FINDREGION_VIRTUALQUERY_ERROR,
  MMPOLICY_RESERVE_FINDREGION_NO_FREE_REGION,
  MMPOLICY_RESERVE_FINAL_RESERVE_ERROR,
};

#if defined(NIGHTLY_BUILD)
struct DetourError {
  // We have a 16-bytes buffer, but only minimum bytes to detour per
  // architecture are copied.  See CreateTrampoline in PatcherDetour.h.
  DetourResultCode mErrorCode;
  uint8_t mOrigBytes[16];
  explicit DetourError(DetourResultCode aError)
      : mErrorCode(aError), mOrigBytes{} {}
  DetourError(DetourResultCode aError, DWORD aWin32Error)
      : mErrorCode(aError), mOrigBytes{} {
    static_assert(sizeof(mOrigBytes) >= sizeof(aWin32Error),
                  "Can't fit a DWORD in mOrigBytes");
    *reinterpret_cast(mOrigBytes) = aWin32Error;
  }
  operator WindowsError() const {
    return WindowsError::FromHResult(mErrorCode);
  }
};
#endif  // defined(NIGHTLY_BUILD)

template 
using WindowsErrorResult = Result;

struct LauncherError {
  LauncherError(const char* aFile, int aLine, WindowsError aWin32Error)
      : mFile(aFile), mLine(aLine), mError(aWin32Error) {}

#if defined(NIGHTLY_BUILD)
  LauncherError(const char* aFile, int aLine,
                const Maybe& aDetourError)
      : mFile(aFile),
        mLine(aLine),
        mError(aDetourError.isSome() ? aDetourError.value()
                                     : WindowsError::CreateGeneric()),
        mDetourError(aDetourError) {}
#endif  // defined(NIGHTLY_BUILD)

  const char* mFile;
  int mLine;
  WindowsError mError;
#if defined(NIGHTLY_BUILD)
  Maybe mDetourError;
#endif  // defined(NIGHTLY_BUILD)

  bool operator==(const LauncherError& aOther) const {
    return mError == aOther.mError;
  }

  bool operator!=(const LauncherError& aOther) const {
    return mError != aOther.mError;
  }

  bool operator==(const WindowsError& aOther) const { return mError == aOther; }

  bool operator!=(const WindowsError& aOther) const { return mError != aOther; }
};

#if defined(MOZ_USE_LAUNCHER_ERROR)

template 
using LauncherResult = Result;

template 
using LauncherResultWithLineInfo = LauncherResult;

using WindowsErrorType = LauncherError;

#else

template 
using LauncherResult = WindowsErrorResult;

template 
using LauncherResultWithLineInfo = Result;

using WindowsErrorType = WindowsError;

#endif  // defined(MOZ_USE_LAUNCHER_ERROR)

using LauncherVoidResult = LauncherResult;

using LauncherVoidResultWithLineInfo = LauncherResultWithLineInfo;

#if defined(MOZ_USE_LAUNCHER_ERROR)

#  define LAUNCHER_ERROR_GENERIC()           \
    ::mozilla::Err(::mozilla::LauncherError( \
        __FILE__, __LINE__, ::mozilla::WindowsError::CreateGeneric()))

#  if defined(NIGHTLY_BUILD)
#    define LAUNCHER_ERROR_FROM_DETOUR_ERROR(err) \
      ::mozilla::Err(::mozilla::LauncherError(__FILE__, __LINE__, err))
#  else
#    define LAUNCHER_ERROR_FROM_DETOUR_ERROR(err) LAUNCHER_ERROR_GENERIC()
#  endif  // defined(NIGHTLY_BUILD)

#  define LAUNCHER_ERROR_FROM_WIN32(err)     \
    ::mozilla::Err(::mozilla::LauncherError( \
        __FILE__, __LINE__, ::mozilla::WindowsError::FromWin32Error(err)))

#  define LAUNCHER_ERROR_FROM_LAST()         \
    ::mozilla::Err(::mozilla::LauncherError( \
        __FILE__, __LINE__, ::mozilla::WindowsError::FromLastError()))

#  define LAUNCHER_ERROR_FROM_NTSTATUS(ntstatus) \
    ::mozilla::Err(::mozilla::LauncherError(     \
        __FILE__, __LINE__, ::mozilla::WindowsError::FromNtStatus(ntstatus)))

#  define LAUNCHER_ERROR_FROM_HRESULT(hresult) \
    ::mozilla::Err(::mozilla::LauncherError(   \
        __FILE__, __LINE__, ::mozilla::WindowsError::FromHResult(hresult)))

// This macro wraps the supplied WindowsError with a LauncherError
#  define LAUNCHER_ERROR_FROM_MOZ_WINDOWS_ERROR(err) \
    ::mozilla::Err(::mozilla::LauncherError(__FILE__, __LINE__, err))

#else

#  define LAUNCHER_ERROR_GENERIC() \
    ::mozilla::Err(::mozilla::WindowsError::CreateGeneric())

#  define LAUNCHER_ERROR_FROM_DETOUR_ERROR(err) LAUNCHER_ERROR_GENERIC()

#  define LAUNCHER_ERROR_FROM_WIN32(err) \
    ::mozilla::Err(::mozilla::WindowsError::FromWin32Error(err))

#  define LAUNCHER_ERROR_FROM_LAST() \
    ::mozilla::Err(::mozilla::WindowsError::FromLastError())

#  define LAUNCHER_ERROR_FROM_NTSTATUS(ntstatus) \
    ::mozilla::Err(::mozilla::WindowsError::FromNtStatus(ntstatus))

#  define LAUNCHER_ERROR_FROM_HRESULT(hresult) \
    ::mozilla::Err(::mozilla::WindowsError::FromHResult(hresult))

#  define LAUNCHER_ERROR_FROM_MOZ_WINDOWS_ERROR(err) ::mozilla::Err(err)

#endif  // defined(MOZ_USE_LAUNCHER_ERROR)

// How long to wait for a created process to become available for input,
// to prevent that process's windows being forced to the background.
// This is used across update, restart, and the launcher.
const DWORD kWaitForInputIdleTimeoutMS = 10 * 1000;

/**
 * Wait for a child GUI process to become "idle." Idle means that the process
 * has created its message queue and has begun waiting for user input.
 *
 * Note that this must only be used when the child process is going to display
 * GUI! Otherwise you're going to be waiting for a very long time ;-)
 *
 * @return true if we successfully waited for input idle;
 *         false if we timed out or failed to wait.
 */
inline bool WaitForInputIdle(HANDLE aProcess,
                             DWORD aTimeoutMs = kWaitForInputIdleTimeoutMS) {
  const DWORD kSleepTimeMs = 10;
  const DWORD waitStart = aTimeoutMs == INFINITE ? 0 : ::GetTickCount();
  DWORD elapsed = 0;

  while (true) {
    if (aTimeoutMs != INFINITE) {
      elapsed = ::GetTickCount() - waitStart;
    }

    if (elapsed >= aTimeoutMs) {
      return false;
    }

    // ::WaitForInputIdle() doesn't always set the last-error code on failure
    ::SetLastError(ERROR_SUCCESS);

    DWORD waitResult = ::WaitForInputIdle(aProcess, aTimeoutMs - elapsed);
    if (!waitResult) {
      return true;
    }

    if (waitResult == WAIT_FAILED &&
        ::GetLastError() == ERROR_NOT_GUI_PROCESS) {
      ::Sleep(kSleepTimeMs);
      continue;
    }

    return false;
  }
}

enum class PathType {
  eNtPath,
  eDosPath,
};

class FileUniqueId final {
 public:
  explicit FileUniqueId(const wchar_t* aPath, PathType aPathType)
      : mId(FILE_ID_INFO()) {
    if (!aPath) {
      mId = LAUNCHER_ERROR_FROM_HRESULT(E_INVALIDARG);
      return;
    }

    nsAutoHandle file;

    switch (aPathType) {
      default:
        mId = LAUNCHER_ERROR_FROM_HRESULT(E_INVALIDARG);
        MOZ_ASSERT_UNREACHABLE("Unhandled PathType");
        return;

      case PathType::eNtPath: {
        UNICODE_STRING unicodeString;
        ::RtlInitUnicodeString(&unicodeString, aPath);
        OBJECT_ATTRIBUTES objectAttributes;
        InitializeObjectAttributes(&objectAttributes, &unicodeString,
                                   OBJ_CASE_INSENSITIVE, nullptr, nullptr);
        IO_STATUS_BLOCK ioStatus = {};
        HANDLE ntHandle;
        NTSTATUS status = ::NtOpenFile(
            &ntHandle, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &objectAttributes,
            &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);
        // We don't need to check |ntHandle| for INVALID_HANDLE_VALUE here,
        // as that value is set by the Win32 layer.
        if (!NT_SUCCESS(status)) {
          mId = LAUNCHER_ERROR_FROM_NTSTATUS(status);
          return;
        }

        file.own(ntHandle);
        break;
      }

      case PathType::eDosPath: {
        file.own(::CreateFileW(
            aPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr));
        if (file == INVALID_HANDLE_VALUE) {
          mId = LAUNCHER_ERROR_FROM_LAST();
          return;
        }

        break;
      }
    }

    GetId(file);
  }

  explicit FileUniqueId(const nsAutoHandle& aFile) : mId(FILE_ID_INFO()) {
    GetId(aFile);
  }

  ~FileUniqueId() = default;

  bool IsError() const { return mId.isErr(); }

  const WindowsErrorType& GetError() const { return mId.inspectErr(); }

  FileUniqueId(FileUniqueId&& aOther) = default;
  FileUniqueId& operator=(FileUniqueId&& aOther) = delete;

  bool operator==(const FileUniqueId& aOther) const {
    return mId.isOk() && aOther.mId.isOk() &&
           !memcmp(&mId.inspect(), &aOther.mId.inspect(), sizeof(FILE_ID_INFO));
  }

  bool operator!=(const FileUniqueId& aOther) const {
    return !((*this) == aOther);
  }

 private:
  void GetId(const nsAutoHandle& aFile) {
    FILE_ID_INFO fileIdInfo = {};
    if (IsWin8OrLater()) {
      if (::GetFileInformationByHandleEx(aFile.get(), FileIdInfo, &fileIdInfo,
                                         sizeof(fileIdInfo))) {
        mId = fileIdInfo;
        return;
      }
      // Only NTFS and ReFS support FileIdInfo. So we have to fallback if
      // GetFileInformationByHandleEx failed.
    }

    BY_HANDLE_FILE_INFORMATION info = {};
    if (!::GetFileInformationByHandle(aFile.get(), &info)) {
      mId = LAUNCHER_ERROR_FROM_LAST();
      return;
    }

    fileIdInfo.VolumeSerialNumber = info.dwVolumeSerialNumber;
    memcpy(&fileIdInfo.FileId.Identifier[0], &info.nFileIndexLow,
           sizeof(DWORD));
    memcpy(&fileIdInfo.FileId.Identifier[sizeof(DWORD)], &info.nFileIndexHigh,
           sizeof(DWORD));
    mId = fileIdInfo;
  }

 private:
  LauncherResult mId;
};

class MOZ_RAII AutoVirtualProtect final {
 public:
  AutoVirtualProtect(void* aAddress, size_t aLength, DWORD aProtFlags,
                     HANDLE aTargetProcess = ::GetCurrentProcess())
      : mAddress(aAddress),
        mLength(aLength),
        mTargetProcess(aTargetProcess),
        mPrevProt(0),
        mError(WindowsError::CreateSuccess()) {
    if (!::VirtualProtectEx(aTargetProcess, aAddress, aLength, aProtFlags,
                            &mPrevProt)) {
      mError = WindowsError::FromLastError();
    }
  }

  ~AutoVirtualProtect() {
    if (mError.IsFailure()) {
      return;
    }

    ::VirtualProtectEx(mTargetProcess, mAddress, mLength, mPrevProt,
                       &mPrevProt);
  }

  explicit operator bool() const { return mError.IsSuccess(); }

  WindowsError GetError() const { return mError; }

  DWORD PrevProt() const { return mPrevProt; }

  AutoVirtualProtect(const AutoVirtualProtect&) = delete;
  AutoVirtualProtect(AutoVirtualProtect&&) = delete;
  AutoVirtualProtect& operator=(const AutoVirtualProtect&) = delete;
  AutoVirtualProtect& operator=(AutoVirtualProtect&&) = delete;

 private:
  void* mAddress;
  size_t mLength;
  HANDLE mTargetProcess;
  DWORD mPrevProt;
  WindowsError mError;
};

inline UniquePtr GetFullModulePath(HMODULE aModule) {
  DWORD bufLen = MAX_PATH;
  mozilla::UniquePtr buf;
  DWORD retLen;

  while (true) {
    buf = mozilla::MakeUnique(bufLen);
    retLen = ::GetModuleFileNameW(aModule, buf.get(), bufLen);
    if (!retLen) {
      return nullptr;
    }

    if (retLen == bufLen && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
      bufLen *= 2;
      continue;
    }

    break;
  }

  // Upon success, retLen *excludes* the null character
  ++retLen;

  // Since we're likely to have a bunch of unused space in buf, let's
  // reallocate a string to the actual size of the file name.
  auto result = mozilla::MakeUnique(retLen);
  if (wcscpy_s(result.get(), retLen, buf.get())) {
    return nullptr;
  }

  return result;
}

inline UniquePtr GetFullBinaryPath() {
  return GetFullModulePath(nullptr);
}

class ModuleVersion final {
 public:
  constexpr ModuleVersion() : mVersion(0ULL) {}

  explicit ModuleVersion(const VS_FIXEDFILEINFO& aFixedInfo)
      : mVersion((static_cast(aFixedInfo.dwFileVersionMS) << 32) |
                 static_cast(aFixedInfo.dwFileVersionLS)) {}

  explicit ModuleVersion(const uint64_t aVersion) : mVersion(aVersion) {}

  ModuleVersion(const ModuleVersion& aOther) : mVersion(aOther.mVersion) {}

  uint64_t AsInteger() const { return mVersion; }

  operator uint64_t() const { return AsInteger(); }

  Tuple AsTuple() const {
    uint16_t major = static_cast((mVersion >> 48) & 0xFFFFU);
    uint16_t minor = static_cast((mVersion >> 32) & 0xFFFFU);
    uint16_t patch = static_cast((mVersion >> 16) & 0xFFFFU);
    uint16_t build = static_cast(mVersion & 0xFFFFU);

    return MakeTuple(major, minor, patch, build);
  }

  explicit operator bool() const { return !!mVersion; }

  bool operator<(const ModuleVersion& aOther) const {
    return mVersion < aOther.mVersion;
  }

  bool operator<(const uint64_t& aOther) const { return mVersion < aOther; }

  ModuleVersion& operator=(const uint64_t aIntVersion) {
    mVersion = aIntVersion;
    return *this;
  }

 private:
  uint64_t mVersion;
};

inline LauncherResult GetModuleVersion(
    const wchar_t* aModuleFullPath) {
  DWORD verInfoLen = ::GetFileVersionInfoSizeW(aModuleFullPath, nullptr);
  if (!verInfoLen) {
    return LAUNCHER_ERROR_FROM_LAST();
  }

  auto verInfoBuf = MakeUnique(verInfoLen);
  if (!::GetFileVersionInfoW(aModuleFullPath, 0, verInfoLen,
                             verInfoBuf.get())) {
    return LAUNCHER_ERROR_FROM_LAST();
  }

  UINT fixedInfoLen;
  VS_FIXEDFILEINFO* fixedInfo = nullptr;
  if (!::VerQueryValueW(verInfoBuf.get(), L"\\",
                        reinterpret_cast(&fixedInfo), &fixedInfoLen)) {
    // VerQueryValue may fail if the resource does not exist. This is not an
    // error; we'll return 0 in this case.
    return ModuleVersion(0ULL);
  }

  return ModuleVersion(*fixedInfo);
}

inline LauncherResult GetModuleVersion(HMODULE aModule) {
  UniquePtr fullPath(GetFullModulePath(aModule));
  if (!fullPath) {
    return LAUNCHER_ERROR_GENERIC();
  }

  return GetModuleVersion(fullPath.get());
}

#if defined(MOZILLA_INTERNAL_API)
inline LauncherResult GetModuleVersion(nsIFile* aFile) {
  if (!aFile) {
    return LAUNCHER_ERROR_FROM_HRESULT(E_INVALIDARG);
  }

  nsAutoString fullPath;
  nsresult rv = aFile->GetPath(fullPath);
  if (NS_FAILED(rv)) {
    return LAUNCHER_ERROR_GENERIC();
  }

  return GetModuleVersion(fullPath.get());
}
#endif  // defined(MOZILLA_INTERNAL_API)

struct CoTaskMemFreeDeleter {
  void operator()(void* aPtr) { ::CoTaskMemFree(aPtr); }
};

inline LauncherResult GetElevationType(
    const nsAutoHandle& aToken) {
  DWORD retLen;
  TOKEN_ELEVATION_TYPE elevationType;
  if (!::GetTokenInformation(aToken.get(), TokenElevationType, &elevationType,
                             sizeof(elevationType), &retLen)) {
    return LAUNCHER_ERROR_FROM_LAST();
  }

  return elevationType;
}

}  // namespace mozilla

Minimal test - lines (41, 44)

path: .spaces[0].metrics.nargs.average
old: 1.0
new: null

path: .spaces[0].metrics.nargs.sum
old: 1.0
new: 0.0

path: .spaces[0].metrics.nexits.average
old: 0.0
new: null

path: .spaces[0].metrics.cognitive.average
old: 4.0
new: null

path: .spaces[0].metrics.cognitive.sum
old: 4.0
new: 0.0

path: .spaces[0].metrics.mi.mi_sei
old: 51.76455993612254
new: 115.02610035996176

path: .spaces[0].metrics.mi.mi_original
old: 74.03847250651805
new: 132.13127313109095

path: .spaces[0].metrics.mi.mi_visual_studio
old: 43.29735234299301
new: 77.26975036905904

path: .spaces[0].metrics.nom.functions
old: 1.0
new: 0.0

path: .spaces[0].metrics.nom.total
old: 1.0
new: 0.0

path: .spaces[0].metrics.cyclomatic.average
old: 3.0
new: 1.0

path: .spaces[0].metrics.cyclomatic.sum
old: 3.0
new: 1.0

path: .spaces[0].metrics.halstead.vocabulary
old: 52.0
new: 7.0

path: .spaces[0].metrics.halstead.volume
old: 1037.4800287016787
new: 22.458839376460833

path: .spaces[0].metrics.halstead.N2
old: 87.0
new: 4.0

path: .spaces[0].metrics.halstead.N1
old: 95.0
new: 4.0

path: .spaces[0].metrics.halstead.time
old: 1327.3641543683243
new: 1.871569948038403

path: .spaces[0].metrics.halstead.effort
old: 23892.55477862984
new: 33.68825906469125

path: .spaces[0].metrics.halstead.n1
old: 18.0
new: 3.0

path: .spaces[0].metrics.halstead.n2
old: 34.0
new: 4.0

path: .spaces[0].metrics.halstead.bugs
old: 0.2765161313707384
new: 0.003476944758806696

path: .spaces[0].metrics.halstead.estimated_program_length
old: 248.03238662847315
new: 12.754887502163468

path: .spaces[0].metrics.halstead.difficulty
old: 23.029411764705884
new: 1.5

path: .spaces[0].metrics.halstead.level
old: 0.043422733077905486
new: 0.6666666666666666

path: .spaces[0].metrics.halstead.length
old: 182.0
new: 8.0

path: .spaces[0].metrics.halstead.purity_ratio
old: 1.3628153111454568
new: 1.5943609377704335

path: .spaces[0].metrics.loc.ploc
old: 35.0
new: 4.0

path: .spaces[0].metrics.loc.lloc
old: 13.0
new: 0.0

path: .spaces[0].metrics.loc.cloc
old: 3.0
new: 0.0

path: .spaces[0].metrics.loc.blank
old: 3.0
new: 0.0

path: .spaces[0].metrics.loc.sloc
old: 41.0
new: 4.0

Code

typedef struct _FILE_ID_INFO {
  ULONGLONG VolumeSerialNumber;
  FILE_ID_128 FileId;
} FILE_ID_INFO;