void
InitTlsAllocationTracker()
{
  if (sInitialized) {
    return;
  }

  sRecentTlsAllocationStacks = new stacks_t();

  // Windows DLL interceptor
  static WindowsDllInterceptor sKernel32DllInterceptor{};

  // Initialize dll interceptor and add hook.
  sKernel32DllInterceptor.Init("kernel32.dll");
  bool succeeded = sKernel32DllInterceptor.AddHook(
    "TlsAlloc",
    reinterpret_cast<intptr_t>(InterposedTlsAlloc),
    reinterpret_cast<void**>(&gOriginalTlsAlloc));

  if (!succeeded) {
    return;
  }

  succeeded = sKernel32DllInterceptor.AddHook(
    "TlsFree",
    reinterpret_cast<intptr_t>(InterposedTlsFree),
    reinterpret_cast<void**>(&gOriginalTlsFree));

  if (!succeeded) {
    return;
  }

  sInitialized = true;
}
void PoisonWrite() {
  // Quick sanity check that we don't poison twice.
  static bool WritesArePoisoned = false;
  MOZ_ASSERT(!WritesArePoisoned);
  if (WritesArePoisoned)
    return;
  WritesArePoisoned = true;

  if (!PoisonWriteEnabled())
    return;

  sNtDllInterceptor.Init("ntdll.dll");
  sNtDllInterceptor.AddHook("NtWriteFile", reinterpret_cast<intptr_t>(patched_WriteFile), reinterpret_cast<void**>(&gOriginalWriteFile));
  sNtDllInterceptor.AddHook("NtWriteFileGather", reinterpret_cast<intptr_t>(patched_WriteFileGather), reinterpret_cast<void**>(&gOriginalWriteFileGather));
}
static void InstallHooks()
{
    gNtdllIntercept.Init("ntdll.dll");
    bool ok = gNtdllIntercept.AddHook("RtlAllocateHeap", reinterpret_cast<intptr_t>(RtlAllocateHeapHook), (void**) &gRtlAllocateHeapOrig);
    if (ok)
        lf("memtrace.dll: Hooked RtlAllocateHeap");
    else
        lf("memtrace.dll: failed to hook RtlAllocateHeap");

    ok = gNtdllIntercept.AddHook("RtlFreeHeap", reinterpret_cast<intptr_t>(RtlFreeHeapHook), (void**) &gRtlFreeHeapOrig);
    if (ok)
        lf("memtrace.dll: Hooked RtlFreeHeap");
    else
        lf("memtrace.dll: failed to hook RtlFreeHeap");
}
void
XRE_SetupDllBlocklist()
{
  NtDllIntercept.Init("ntdll.dll");

  bool ok = NtDllIntercept.AddHook("LdrLoadDll", reinterpret_cast<intptr_t>(patched_LdrLoadDll), (void**) &stub_LdrLoadDll);

#ifdef DEBUG
  if (!ok)
    printf_stderr ("LdrLoadDll hook failed, no dll blocklisting active\n");
#endif
}
bool TestHook(const char *dll, const char *func)
{
  void *orig_func;
  WindowsDllInterceptor TestIntercept;
  TestIntercept.Init(dll);
  if (TestIntercept.AddHook(func, 0, &orig_func)) {
    printf("TEST-PASS | WindowsDllInterceptor | Could hook %s from %s\n", func, dll);
    return true;
  } else {
    printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll);
    return false;
  }
}
bool TestHook(HookTestFunc funcTester, const char *dll, const char *func)
{
  void *orig_func;
  bool successful = false;
  {
    WindowsDllInterceptor TestIntercept;
    TestIntercept.Init(dll);
    successful = TestIntercept.AddHook(func, 0, &orig_func);
  }

  if (successful) {
    printf("TEST-PASS | WindowsDllInterceptor | Could hook %s from %s\n", func, dll);
    return CheckHook(funcTester, orig_func, dll, func);
  } else {
    printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to hook %s from %s\n", func, dll);
    return false;
  }
}
int main()
{
  payload initial = { 0x12345678, 0xfc4e9d31, 0x87654321 };
  payload p0, p1;
  ZeroMemory(&p0, sizeof(p0));
  ZeroMemory(&p1, sizeof(p1));

  p0 = rotatePayload(initial);

  {
    WindowsDllInterceptor ExeIntercept;
    ExeIntercept.Init("TestDllInterceptor.exe");
    if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast<intptr_t>(patched_rotatePayload), (void**) &orig_rotatePayload)) {
      printf("TEST-PASS | WindowsDllInterceptor | Hook added\n");
    } else {
      printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n");
      return 1;
    }

    p1 = rotatePayload(initial);

    if (patched_func_called) {
      printf("TEST-PASS | WindowsDllInterceptor | Hook called\n");
    } else {
      printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was not called\n");
      return 1;
    }

    if (p0 == p1) {
      printf("TEST-PASS | WindowsDllInterceptor | Hook works properly\n");
    } else {
      printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook didn't return the right information\n");
      return 1;
    }
  }

  patched_func_called = false;
  ZeroMemory(&p1, sizeof(p1));

  p1 = rotatePayload(initial);

  if (!patched_func_called) {
    printf("TEST-PASS | WindowsDllInterceptor | Hook was not called after unregistration\n");
  } else {
    printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was still called after unregistration\n");
    return 1;
  }

  if (p0 == p1) {
    printf("TEST-PASS | WindowsDllInterceptor | Original function worked properly\n");
  } else {
    printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Original function didn't return the right information\n");
    return 1;
  }

  if (TestHook("user32.dll", "GetWindowInfo") &&
#ifdef _WIN64
      TestHook("user32.dll", "SetWindowLongPtrA") &&
      TestHook("user32.dll", "SetWindowLongPtrW") &&
#else
      TestHook("user32.dll", "SetWindowLongA") &&
      TestHook("user32.dll", "SetWindowLongW") &&
#endif
      TestHook("user32.dll", "TrackPopupMenu") &&
      TestHook("ntdll.dll", "NtFlushBuffersFile") &&
      TestHook("ntdll.dll", "LdrLoadDll")) {
    printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
    return 0;
  }

  return 1;
}
int main()
{
  payload initial = { 0x12345678, 0xfc4e9d31, 0x87654321 };
  payload p0, p1;
  ZeroMemory(&p0, sizeof(p0));
  ZeroMemory(&p1, sizeof(p1));

  p0 = rotatePayload(initial);

  {
    WindowsDllInterceptor ExeIntercept;
    ExeIntercept.Init("TestDllInterceptor.exe");
    if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast<intptr_t>(patched_rotatePayload), (void**) &orig_rotatePayload)) {
      printf("TEST-PASS | WindowsDllInterceptor | Hook added\n");
    } else {
      printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n");
      return 1;
    }

    p1 = rotatePayload(initial);

    if (patched_func_called) {
      printf("TEST-PASS | WindowsDllInterceptor | Hook called\n");
    } else {
      printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was not called\n");
      return 1;
    }

    if (p0 == p1) {
      printf("TEST-PASS | WindowsDllInterceptor | Hook works properly\n");
    } else {
      printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook didn't return the right information\n");
      return 1;
    }
  }

  patched_func_called = false;
  ZeroMemory(&p1, sizeof(p1));

  p1 = rotatePayload(initial);

  if (!patched_func_called) {
    printf("TEST-PASS | WindowsDllInterceptor | Hook was not called after unregistration\n");
  } else {
    printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was still called after unregistration\n");
    return 1;
  }

  if (p0 == p1) {
    printf("TEST-PASS | WindowsDllInterceptor | Original function worked properly\n");
  } else {
    printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Original function didn't return the right information\n");
    return 1;
  }

  if (TestHook("user32.dll", "GetWindowInfo") &&
#ifdef _WIN64
      TestHook("user32.dll", "SetWindowLongPtrA") &&
      TestHook("user32.dll", "SetWindowLongPtrW") &&
#else
      TestHook("user32.dll", "SetWindowLongA") &&
      TestHook("user32.dll", "SetWindowLongW") &&
#endif
      TestHook("user32.dll", "TrackPopupMenu") &&
#ifdef _M_IX86
      // We keep this test to hook complex code on x86. (Bug 850957)
      TestHook("ntdll.dll", "NtFlushBuffersFile") &&
#endif
      TestHook("ntdll.dll", "NtWriteFile") &&
      TestHook("ntdll.dll", "NtWriteFileGather") &&
      // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp
      TestHook("kernel32.dll", "SetUnhandledExceptionFilter") &&
#ifdef _M_IX86
      // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp
      TestHook("kernel32.dll", "VirtualAlloc") &&
      TestHook("kernel32.dll", "MapViewOfFile") &&
      TestHook("gdi32.dll", "CreateDIBSection") &&
#endif
      TestHook("ntdll.dll", "LdrLoadDll")) {
    printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
    return 0;
  }

  return 1;
}
int main()
{
  payload initial = { 0x12345678, 0xfc4e9d31, 0x87654321 };
  payload p0, p1;
  ZeroMemory(&p0, sizeof(p0));
  ZeroMemory(&p1, sizeof(p1));

  p0 = rotatePayload(initial);

  {
    WindowsDllInterceptor ExeIntercept;
    ExeIntercept.Init("TestDllInterceptor.exe");
    if (ExeIntercept.AddHook("rotatePayload", reinterpret_cast<intptr_t>(patched_rotatePayload), (void**) &orig_rotatePayload)) {
      printf("TEST-PASS | WindowsDllInterceptor | Hook added\n");
    } else {
      printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Failed to add hook\n");
      return 1;
    }

    p1 = rotatePayload(initial);

    if (patched_func_called) {
      printf("TEST-PASS | WindowsDllInterceptor | Hook called\n");
    } else {
      printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was not called\n");
      return 1;
    }

    if (p0 == p1) {
      printf("TEST-PASS | WindowsDllInterceptor | Hook works properly\n");
    } else {
      printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook didn't return the right information\n");
      return 1;
    }
  }

  patched_func_called = false;
  ZeroMemory(&p1, sizeof(p1));

  p1 = rotatePayload(initial);

  if (!patched_func_called) {
    printf("TEST-PASS | WindowsDllInterceptor | Hook was not called after unregistration\n");
  } else {
    printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Hook was still called after unregistration\n");
    return 1;
  }

  if (p0 == p1) {
    printf("TEST-PASS | WindowsDllInterceptor | Original function worked properly\n");
  } else {
    printf("TEST-UNEXPECTED-FAIL | WindowsDllInterceptor | Original function didn't return the right information\n");
    return 1;
  }

  if (TestHook(TestGetWindowInfo, "user32.dll", "GetWindowInfo") &&
#ifdef _WIN64
      TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrA") &&
      TestHook(TestSetWindowLongPtr, "user32.dll", "SetWindowLongPtrW") &&
#else
      TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongA") &&
      TestHook(TestSetWindowLong, "user32.dll", "SetWindowLongW") &&
#endif
      TestHook(TestTrackPopupMenu, "user32.dll", "TrackPopupMenu") &&
#ifdef _M_IX86
      // We keep this test to hook complex code on x86. (Bug 850957)
      TestHook(TestNtFlushBuffersFile, "ntdll.dll", "NtFlushBuffersFile") &&
#endif
      TestHook(TestNtCreateFile, "ntdll.dll", "NtCreateFile") &&
      TestHook(TestNtReadFile, "ntdll.dll", "NtReadFile") &&
      TestHook(TestNtReadFileScatter, "ntdll.dll", "NtReadFileScatter") &&
      TestHook(TestNtWriteFile, "ntdll.dll", "NtWriteFile") &&
      TestHook(TestNtWriteFileGather, "ntdll.dll", "NtWriteFileGather") &&
      TestHook(TestNtQueryFullAttributesFile, "ntdll.dll", "NtQueryFullAttributesFile") &&
      // Bug 733892: toolkit/crashreporter/nsExceptionHandler.cpp
      TestHook(TestSetUnhandledExceptionFilter, "kernel32.dll", "SetUnhandledExceptionFilter") &&
#ifdef _M_IX86
      // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp
      TestHook(TestVirtualAlloc, "kernel32.dll", "VirtualAlloc") &&
      TestHook(TestMapViewOfFile, "kernel32.dll", "MapViewOfFile") &&
      TestHook(TestCreateDIBSection, "gdi32.dll", "CreateDIBSection") &&
      TestHook(TestCreateFileW, "kernel32.dll", "CreateFileW") &&    // see Bug 1316415
#endif
      TestHook(TestCreateFileA, "kernel32.dll", "CreateFileA") &&
      TestDetour("user32.dll", "CreateWindowExW") &&
      TestHook(TestInSendMessageEx, "user32.dll", "InSendMessageEx") &&
      TestHook(TestImmGetContext, "imm32.dll", "ImmGetContext") &&
      // TestHook("imm32.dll", "ImmReleaseContext") &&    // see Bug 1316415
      TestHook(TestImmGetCompositionStringW, "imm32.dll", "ImmGetCompositionStringW") &&
      TestHook(TestImmSetCandidateWindow, "imm32.dll", "ImmSetCandidateWindow") &&
      TestHook(TestImmNotifyIME, "imm32.dll", "ImmNotifyIME") &&
      TestHook(TestGetSaveFileNameW, "comdlg32.dll", "GetSaveFileNameW") &&
      TestHook(TestGetOpenFileNameW, "comdlg32.dll", "GetOpenFileNameW") &&
#ifdef _M_X64
      TestHook(TestGetKeyState, "user32.dll", "GetKeyState") &&    // see Bug 1316415
      TestHook(TestLdrUnloadDll, "ntdll.dll", "LdrUnloadDll") &&
      MaybeTestHook(IsWin8OrLater(), TestLdrResolveDelayLoadedAPI, "ntdll.dll", "LdrResolveDelayLoadedAPI") &&
      MaybeTestHook(!IsWin8OrLater(), TestRtlInstallFunctionTableCallback, "kernel32.dll", "RtlInstallFunctionTableCallback") &&
#endif
      MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") &&
#ifdef _M_IX86
      TestHook(TestSendMessageTimeoutW, "user32.dll", "SendMessageTimeoutW") &&
#endif
      TestHook(TestTlsAlloc, "kernel32.dll", "TlsAlloc") &&
      TestHook(TestTlsFree, "kernel32.dll", "TlsFree") &&
      TestDetour("ntdll.dll", "LdrLoadDll")) {
    printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
    return 0;
  }

  return 1;
}