Conversation
Jakobzs
marked this pull request as ready for review
July 20, 2026 06:01
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
This PR fixes three correctness and safety problems found while reviewing the wrapper.
1. Make Rust-function hooks work in optimized builds
Problem: The README and integration tests called locally defined Rust functions directly. In release builds, the optimizer could constant-fold or otherwise bypass the patched entry point, so MinHook reported success while the original function still ran.
Solution:
#[inline(never)]std::hint::black_boxWhy this solves it: The opaque indirect call must go through the function address that MinHook patched, instead of allowing the compiler to replace the call with a known result. The previously failing release tests now pass on both x64 and i686.
2. Enforce and test the correct Win32 calling convention
Problem: The API-hook tests used Rust-ABI
fnpointers for Win32 functions. That happened to work for the zero-argumentGetCurrentProcessIdtest, but a Win32 function with stack arguments crashes on 32-bit Windows becauseextern "system"uses the platform system calling convention.Solution:
extern "system"Sleep(u32), invokes its trampoline, and runs on i686Why this solves it: Detours and trampolines now use the same ABI as the target API, including the 32-bit Windows stack-cleanup convention. The argument-bearing regression test passes on both architectures and would catch the previous mismatch.
3. Make initialization ownership and teardown explicit
Problem: Two independent
Oncevalues made teardown irreversible, initialization failures panic, anduninitialize()safe even though native teardown invalidates trampoline memory. The wrapper also treatedMH_ERROR_ALREADY_INITIALIZEDas success and could later tear down a MinHook instance owned by another component.Solution:
Oncevalues with a mutex-protected lifecycle stateResultAPIsuninitialize()unsafe and fallibleWhy this solves it: Teardown can no longer happen through a safe API without acknowledging trampoline-lifetime requirements, native failures are returned instead of panicking, and the wrapper only calls native
MH_Uninitializefor initialization it owns.API impact
MinHook::uninitialize()is now:This is an intentional breaking change because callers must prove that no detour or trampoline remains in use before native executable buffers are freed.
Validation
cargo fmt --all -- --check-D clippy::allon x64 and i686