Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/detours.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2023,6 +2023,22 @@ LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
return ERROR_INVALID_PARAMETER;
}

#ifdef DETOURS_X64
// Detouring a function should not break our ability to walk the call stack.
// On X64 stack unwinding relies on RUNTIME_FUNCTION structures.
// Require this.
// These are typically found in the .pdata section of PE32+ images.
// Alternatively dynamic code should use RtlAddGrowableFunctionTable
// to register this information. This supports kernel stack walks.
// See https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64
DWORD64 imageBase;
if (NULL == RtlLookupFunctionEntry((DWORD64)pDetour, &imageBase, NULL)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some cases, A Detour function could legitimately be a leaf function and thus have no function table entry, so having this requirement is somewhat over-strict.
Regardless, this shouldn't be just DETOURS_X64 specific - function table unwinding is also used on ARM64, for example.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: leaf functions
Table entries are also required for any functions that allocate stack space.

But point taken that the detour could be a very simple function.
The first version of this PR simply checked for MEM_IMAGE - and trusted the compiler to have done its job. On consideration though I changed this to the function table lookup - since I didn't want to entirely preclude the use of a JIT detour. A combination of these two approaches would seem reasonable.

re: ARM64
Agreed, but that's not something I felt comfortable writing.

DETOUR_TRACE(("detour must have entry in function table\n"));
DETOUR_BREAK();
return ERROR_INVALID_PARAMETER;
}
#endif // DETOURS_X64

if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
DETOUR_TRACE(("transaction conflict with thread id=%ld\n", s_nPendingThreadId));
return ERROR_INVALID_OPERATION;
Expand Down