Skip to content

perf(memory): VEH fault guard for MinGW seh_read#118

Merged
tkhquang merged 2 commits into
mainfrom
perf/mingw-seh-read-veh
Jun 12, 2026
Merged

perf(memory): VEH fault guard for MinGW seh_read#118
tkhquang merged 2 commits into
mainfrom
perf/mingw-seh-read-veh

Conversation

@tkhquang

@tkhquang tkhquang commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

On MinGW the seh_read family (seh_read_bytes, read_ptr_unsafe, the pointer-chain reads) paid a VirtualQuery syscall on every guarded read because GCC has no zero-cost frame-based SEH. This replaces that with a single process-wide vectored exception handler, so the success path is a guarded copy with no syscall and a read fault is recovered instead of crashing the host. It also closes a stale-cache unguarded dereference that could crash on a page reprotected out from under the cache. The MSVC __try path is unchanged.

Notes

  • The per-thread guard is published through an allocation-free Win32 TLS slot so the handler is safe in the exception-dispatch context; in-flight reads are drained before the handler is removed, and a VirtualQuery-validated path covers handler-install failure and 32-bit builds.
  • Bench (MinGW Release): a terminal guarded read drops from about 224 ns to about 62 ns, and a six-link chain resolve from about 1.3 us of syscalls to about 250 ns. The MinGW to MSVC gap is inherent (MSVC table-driven SEH is free on the success path).
  • Full memory suite green on both MinGW and MSVC, with new tests for the stale-cache, unarmed-thread pass-through, wraparound, thread-isolation, and shutdown-drain paths. AGENTS.md, README.md, the hot-path and RTTI notes, and the bench data are updated.

Summary by CodeRabbit

  • Documentation

    • Updated memory utility documentation to clarify fault-handling behavior and safety mechanisms.
    • Added benchmark documentation for memory read performance analysis.
  • Performance

    • Optimized memory read operations with improved fault-guard implementation.
  • Tests

    • Added regression tests covering memory read safety, thread isolation, concurrent scenarios, and handler coexistence.

Guard MinGW seh_read_bytes/read_ptr_unsafe with a process-wide vectored exception handler instead of a per-call VirtualQuery: zero-syscall success path recovered via non-unwinding __builtin_setjmp/longjmp, also closing the stale-cache unguarded dereference. Per-thread guard via an allocation-free Win32 TLS slot, drained before handler removal, with a VirtualQuery fallback for install failure and 32-bit builds. MSVC __try path unchanged.
@tkhquang tkhquang self-assigned this Jun 12, 2026
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@tkhquang, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 44 minutes and 7 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 044624d6-48c5-4d03-b3bf-b49117176c15

📥 Commits

Reviewing files that changed from the base of the PR and between 3c5ac00 and ddfa275.

📒 Files selected for processing (2)
  • docs/misc/hot-path-memory.md
  • tests/test_memory.cpp
📝 Walkthrough

Walkthrough

This PR replaces MinGW memory read fault handling from per-region VirtualQuery validation with a process-wide vectored exception handler (VEH) mechanism. The core implementation adds guarded-copy and longjmp-based fault recovery, refactors read_ptr_unsafe and seh_read_bytes APIs to route through the new primitive, and introduces comprehensive documentation and test coverage for fault handling, handler coexistence, and concurrent behaviors.

Changes

MinGW VEH-Based Memory Read Safety

Layer / File(s) Summary
VEH Handler Infrastructure & Guarded Read Primitives
src/memory.cpp
Adds MinGW x64 vectored exception handler with TLS-tracked in-flight reads, setjmp/longjmp fault recovery, handler install/uninstall in init/shutdown paths, and veh_read_bytes entry point with VirtualQuery fallback for 32-bit or handler-install failure.
Memory API Routing Through VEH
src/memory.cpp
Routes read_ptr_unsafe and seh_read_bytes through veh_read_bytes on MinGW, eliminating cache-probe lookups and per-region VirtualQuery validation loops; updates chain-read comments to reflect guarded-link approach.
Header & Public Documentation Updates
include/DetourModKit/memory.hpp, README.md
Updates Doxygen comments for read_ptr_unsafe, read_ptr_unchecked, seh_read_bytes, and seh_resolve_chain to describe MinGW vectored-handler fault handling, swallowed-fault return semantics, and VirtualQuery fallback behavior.
Hot-Path & Analysis Documentation
AGENTS.md, docs/misc/hot-path-memory.md, docs/misc/rtti-walker.md, docs/analysis/memory_veh_bench_v3.x/README.md, tests/bench_memory.cpp
Clarifies MinGW VEH mechanism across scanning guidance, hot-path probe patterns, RTTI walker cold paths, benchmark setup/results, and toolchain descriptor; revises syscall comparisons and removes prior VirtualQuery-loop descriptions.
Fault Handling & Concurrency Tests
tests/test_memory.cpp, tests/test_scanner.cpp
Adds comprehensive regression suite: fail-closed semantics (reserved/uncommitted reads, wraparound), stale-cache detection, handler coexistence with consumer VEH, thread isolation under concurrency, concurrent init/shutdown stress, and unarmed-thread fault non-hijacking; updates test explanations and guard-page comments.

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

  • tkhquang/DetourModKit#44: Introduced the hot-path APIs Memory::read_ptr_unsafe and readability helpers that this PR refactors for MinGW VEH-based guarding.
  • tkhquang/DetourModKit#50: Modified MinGW read_ptr_unsafe and permission-check behavior that this PR replaces with VEH-based guarded-read implementation.
  • tkhquang/DetourModKit#113: Introduced guarded-read fault-predicate filtering machinery in src/memory.cpp that overlaps with this PR's new VEH handler semantics and guard logic.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: implementing a VEH fault guard for MinGW's seh_read family, which is the primary performance optimization across this changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/misc/hot-path-memory.md`:
- Around line 117-120: Update the MinGW documentation to explain that
veh_read_bytes in src/memory.cpp uses the VEH guarded-copy only when
ensure_veh_installed() succeeds (i.e., s_veh_handle is non-null); if handler
installation fails or on 32-bit MinGW (! _WIN64) it falls back to
virtualquery_validated_copy (VirtualQuery-validated copy), so seh_* reads are
best-effort and may use VEH→VirtualQuery fallback rather than always using the
process-wide VEH.

In `@tests/test_memory.cpp`:
- Around line 2339-2374: The test GuardedReadsSurviveConcurrentShutdown races
the shutdown/init loop against readers so it may never exercise the guarded-read
path; modify the test to wait until at least one successful good-path read and
one faulting-path read have been observed before starting the 12-cycle loop.
Instrument the reader lambda that calls Memory::read_ptr_unsafe to increment two
std::atomic<int> counters (e.g., seen_good and seen_fault) depending on whether
the target was the committed page or the freed page, then before the first call
to Memory::shutdown_cache()/Memory::init_cache() spin-wait or block until
seen_good.load() > 0 && seen_fault.load() > 0 (or use a condition_variable) so
the shutdown exercises the drain path; keep the rest of the teardown (stop,
join, final EXPECT_EQ) unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ea12cab4-646c-402d-a3ac-eacf8ff9d1dd

📥 Commits

Reviewing files that changed from the base of the PR and between f3fa1d4 and 3c5ac00.

📒 Files selected for processing (10)
  • AGENTS.md
  • README.md
  • docs/analysis/memory_veh_bench_v3.x/README.md
  • docs/misc/hot-path-memory.md
  • docs/misc/rtti-walker.md
  • include/DetourModKit/memory.hpp
  • src/memory.cpp
  • tests/bench_memory.cpp
  • tests/test_memory.cpp
  • tests/test_scanner.cpp

Comment thread docs/misc/hot-path-memory.md
Comment thread tests/test_memory.cpp
Wait for a live good-path and faulting-path guarded read before the shutdown/init loop so it exercises the in-flight drain rather than possibly racing ahead of any guarded read. Also clarify in hot-path-memory.md that MinGW seh_* takes the VEH guarded-copy path only when the handler installed, and falls back to a VirtualQuery-validated copy on install failure or 32-bit builds.
@tkhquang tkhquang merged commit 20a5935 into main Jun 12, 2026
3 of 4 checks passed
@tkhquang tkhquang deleted the perf/mingw-seh-read-veh branch June 12, 2026 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant