./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
1654 / 1907
86.7%
Branches:
854 / 1249
68.4%
Functions:
199 / 210
94.8%

src/hook.cpp
Line Branch Exec Source
1 /**
2 * @file hook.cpp
3 * @brief This TU implements hook lifecycle: install verbs, RAII handle teardown, and the VMT surface.
4 */
5
6 #include "DetourModKit/hook.hpp"
7
8 #include "internal/hook_backend.hpp"
9 #include "internal/hook_backend_visit.hpp"
10 #include "internal/hook_coordinator.hpp"
11 #include "internal/hook_emission.hpp"
12 #include "internal/hook_fault_boundary.hpp"
13 #include "internal/hook_ledger.hpp"
14 #include "internal/hook_patch_witness.hpp"
15 #include "internal/hook_publication.hpp"
16 #include "internal/lifecycle_context.hpp"
17
18 #include "internal/drain_backoff.hpp"
19 #include "internal/memory_guarded.hpp"
20 #include "internal/mid_hook_adapter.hpp"
21 #include "internal/scan_pages.hpp"
22
23 #include "DetourModKit/diagnostics.hpp"
24 #include "DetourModKit/format.hpp"
25 #include "DetourModKit/logger.hpp"
26
27 #include "platform.hpp"
28 #include "x86_decode.hpp"
29
30 #include <windows.h>
31
32 #include <intrin.h>
33
34 #include <algorithm>
35 #include <array>
36 #include <atomic>
37 #include <chrono>
38 #include <cstddef>
39 #include <cstdint>
40 #include <expected>
41 #include <format>
42 #include <functional>
43 #include <limits>
44 #include <memory>
45 #include <mutex>
46 #include <new>
47 #include <optional>
48 #include <shared_mutex>
49 #include <string>
50 #include <string_view>
51 #include <type_traits>
52 #include <utility>
53 #include <variant>
54 #include <vector>
55
56 namespace DetourModKit::detail
57 {
58 namespace
59 {
60 /// The sentence that names the first refusal of an idle proof, or an empty sentence for a clean proof.
61 struct IdleRefusalSentence
62 {
63 std::array<char, 96> text{};
64 std::size_t size{0};
65
66 350 [[nodiscard]] std::string_view view() const noexcept { return {text.data(), size}; }
67 };
68
69 /// Names the thread and the check of @p refusal. A teardown warning appends the sentence after its reason.
70 16323 [[nodiscard]] IdleRefusalSentence describe_idle_refusal(const safetyhook::IdleRefusal &refusal) noexcept
71 {
72 16323 IdleRefusalSentence sentence{};
73 17 const auto write = [&sentence, &refusal](std::format_string<std::uint32_t> format) noexcept
74 {
75 try
76 {
77
1/2
✓ Branch 6 → 7 taken 17 times.
✗ Branch 6 → 12 not taken.
17 const auto written = std::format_to_n(
78 17 sentence.text.data(),
79 17 static_cast<std::ptrdiff_t>(sentence.text.size()),
80 format,
81 17 std::uint32_t{refusal.thread_id}
82 );
83 34 sentence.size = std::min(static_cast<std::size_t>(written.size), sentence.text.size());
84 }
85 ✗ catch (...)
86 {
87 ✗ sentence.size = 0;
88 ✗ }
89 17 };
90
3/9
✓ Branch 2 → 3 taken 16306 times.
✓ Branch 2 → 4 taken 15 times.
✓ Branch 2 → 6 taken 2 times.
✗ Branch 2 → 8 not taken.
✗ Branch 2 → 10 not taken.
✗ Branch 2 → 12 not taken.
✗ Branch 2 → 14 not taken.
✗ Branch 2 → 16 not taken.
✗ Branch 2 → 18 not taken.
16323 switch (refusal.check)
91 {
92 16306 case safetyhook::IdleRefusalCheck::None:
93 16306 break;
94 15 case safetyhook::IdleRefusalCheck::InstructionPointerInRange:
95 15 write(" Thread {} runs inside the retired code.");
96 15 break;
97 2 case safetyhook::IdleRefusalCheck::ReturnSiteOnStack:
98 2 write(" Thread {} can still return into the retired code.");
99 2 break;
100 ✗ case safetyhook::IdleRefusalCheck::SuspensionFailed:
101 ✗ write(" Thread {} did not suspend.");
102 ✗ break;
103 ✗ case safetyhook::IdleRefusalCheck::ContextFailed:
104 ✗ write(" The context of thread {} is not readable.");
105 ✗ break;
106 ✗ case safetyhook::IdleRefusalCheck::ThreadWalkFailed:
107 ✗ write(" The thread walk failed.");
108 ✗ break;
109 ✗ case safetyhook::IdleRefusalCheck::ThreadLimit:
110 ✗ write(" The process has more threads than one idle pass holds.");
111 ✗ break;
112 ✗ case safetyhook::IdleRefusalCheck::CoordinatorUnavailable:
113 ✗ write(" The process coordinator was unavailable.");
114 ✗ break;
115 }
116 16323 return sentence;
117 }
118 } // namespace
119
120 #if defined(DMK_ENABLE_TEST_SEAMS)
121 namespace
122 {
123 std::atomic<std::uint64_t> s_hook_impl_destructions{0};
124 } // namespace
125
126 std::atomic<std::size_t> g_backend_toggle_exception_catches{0};
127
128 4 std::uint64_t hook_impl_destruction_count_for_test() noexcept
129 {
130 4 return s_hook_impl_destructions.load(std::memory_order_relaxed);
131 }
132
133 16787 void note_hook_impl_destruction_for_test() noexcept
134 {
135 s_hook_impl_destructions.fetch_add(1, std::memory_order_relaxed);
136 16787 }
137
138 // The test-only acquire_hook_self_ref() override lets the suite drive the otherwise-unreachable acquire failure
139 // branch. The override must SetLastError before a nullptr return to satisfy error.hpp's `detail = GetLastError()`
140 // contract.
141 HMODULE (*g_hook_module_ref_override)() noexcept = nullptr;
142
143 // Overrides the byte witness Hook::enable() takes after the backend reports a successful patch. The suite can then
144 // drive the negative branch a real backend does not produce on demand.
145 bool (*g_hook_enable_witness_override)(bool) noexcept = nullptr;
146 // Runs after a managed backend disable returns or throws and before DMK witnesses its target bytes.
147 void (*g_hook_backend_disable_probe)() noexcept = nullptr;
148 // Overrides whether ~Hook attempts backend disable. A false return or exception models a pre-mutation failure.
149 // It leaves the target patched. Post-process after a completed disable makes the pin unobservable.
150 bool (*g_hook_teardown_restore_override)() = nullptr;
151 // Fires at each inline/mid publication step after that step's state is visible. It is not noexcept on purpose.
152 // A probe exception exercises the same rollback as a real bad_alloc.
153 void (*g_hook_publish_probe)(HookPublishStep) = nullptr;
154 // HookTogglePublicationOrder.* owns this proof seam.
155 void (*g_hook_toggle_publication_probe)(bool, bool, bool, bool) noexcept = nullptr;
156 // Fires at the first operation boundary after one mutation entry passes its loader-lock veto.
157 void (*g_hook_post_loader_veto_probe)(HookLoaderEntry) noexcept = nullptr;
158 // Withholds the position claim from inline_at and mid_at, so every install is fresh and every new cell is
159 // unclaimable. The residue budget proofs need positions that no successor takes.
160 std::atomic<bool> g_hook_position_claims_refused_for_test{false};
161 // This probe fires after the vtable pre-count and before the guarded snapshot capture.
162 void (*g_vmt_before_capture_probe)() noexcept = nullptr;
163 // This probe fires after the captured slot count becomes fixed and before the backend sizes its clone.
164 void (*g_vmt_before_backend_clone_probe)() noexcept = nullptr;
165 // This probe fires after VMT validation and before the guarded atomic publication attempt.
166 void (*g_vmt_before_publish_probe)(void *) noexcept = nullptr;
167 // This probe fires after the VMT object gate release and before the leak warning reaches the logger.
168 void (*g_vmt_teardown_warning_probe)() noexcept = nullptr;
169
170 // Arms the backend's post-commit transaction seam for one target, or disarms it with nullptr. The backend can
171 // return an error over a fully committed patch. enable() and disable() reconcile that exact state. This translation
172 // unit forwards the seam because only it names the backend.
173 12 void set_backend_reprotect_failure_target(void *target) noexcept
174 {
175 12 safetyhook::g_trap_restore_failure_override.store(
176 static_cast<std::uint8_t *>(target),
177 std::memory_order_release
178 );
179 12 }
180
181 // Arms a backend bad_alloc after transaction setup but before its mutation callback, or immediately after that
182 // callback. trap_threads still restores protections and removes its trap before it rethrows into DMK's boundary.
183 60 void set_backend_toggle_exception_for_test(void *target, bool after_mutation) noexcept
184 {
185
2/2
✓ Branch 2 → 3 taken 32 times.
✓ Branch 2 → 6 taken 28 times.
60 if (target == nullptr)
186 {
187 32 safetyhook::g_trap_exception_stage_override.store(
188 safetyhook::TrapExceptionStage::NONE,
189 std::memory_order_release
190 );
191 32 safetyhook::g_trap_exception_target_override.store(nullptr, std::memory_order_relaxed);
192 32 return;
193 }
194
195 g_backend_toggle_exception_catches.store(0, std::memory_order_relaxed);
196 28 safetyhook::g_trap_exception_target_override.store(
197 static_cast<std::uint8_t *>(target),
198 std::memory_order_relaxed
199 );
200
2/2
✓ Branch 15 → 16 taken 14 times.
✓ Branch 15 → 17 taken 14 times.
28 safetyhook::g_trap_exception_stage_override.store(
201 after_mutation ? safetyhook::TrapExceptionStage::AFTER_MUTATION
202 : safetyhook::TrapExceptionStage::BEFORE_MUTATION,
203 std::memory_order_release
204 );
205 }
206
207 /// Reports how many managed backend exceptions the current test arm reached and contained.
208 25 std::size_t backend_toggle_exception_catches_for_test() noexcept
209 {
210 25 return g_backend_toggle_exception_catches.load(std::memory_order_relaxed);
211 }
212
213 2 void set_backend_trap_transaction_hold_for_test(bool hold) noexcept
214 {
215
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 1 time.
2 if (hold)
216 {
217 1 safetyhook::g_trap_transaction_reached.store(false, std::memory_order_relaxed);
218 }
219 2 safetyhook::g_trap_transaction_hold.store(hold, std::memory_order_release);
220 2 }
221
222 3366 bool backend_trap_transaction_reached_for_test() noexcept
223 {
224 3366 return safetyhook::g_trap_transaction_reached.load(std::memory_order_acquire);
225 }
226
227 20 std::size_t backend_trap_protect_calls_for_test() noexcept
228 {
229 20 return safetyhook::g_trap_protect_calls.load(std::memory_order_relaxed);
230 }
231
232 14 std::size_t backend_idle_pass_calls_for_test() noexcept
233 {
234 14 return safetyhook::g_idle_pass_calls.load(std::memory_order_relaxed);
235 }
236
237 ✗ void set_backend_idle_scan_hold_for_test(bool hold) noexcept
238 {
239
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ if (hold)
240 {
241 ✗ safetyhook::g_route_scan_reached.store(false);
242 }
243 ✗ safetyhook::g_route_scan_hold.store(hold);
244 ✗ }
245
246 ✗ bool backend_idle_scan_reached_for_test() noexcept
247 {
248 ✗ return safetyhook::g_route_scan_reached.load();
249 }
250
251 6 std::size_t backend_idle_snapshot_walks_for_test() noexcept
252 {
253 6 return safetyhook::g_idle_pass_snapshot_walks.load(std::memory_order_relaxed);
254 }
255
256 2 void fail_backend_next_thread_lookup_for_test(bool fail) noexcept
257 {
258 2 safetyhook::g_next_thread_lookup_failure.store(fail);
259 2 }
260
261 6 bool backend_idle_pass_for_test(void *begin, void *end) noexcept
262 {
263 const std::array<safetyhook::AddressRange, 1> ranges{{{
264 static_cast<std::uint8_t *>(begin),
265 static_cast<std::uint8_t *>(end),
266 6 }}};
267 try
268 {
269
1/2
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 15 not taken.
6 const std::expected<bool, safetyhook::OsError> idle = safetyhook::threads_idle_outside(ranges, {});
270
3/4
✓ Branch 6 → 7 taken 6 times.
✗ Branch 6 → 10 not taken.
✓ Branch 8 → 9 taken 3 times.
✓ Branch 8 → 10 taken 3 times.
6 return idle.has_value() && *idle;
271 }
272 ✗ catch (...)
273 {
274 ✗ return false;
275 ✗ }
276 }
277
278 10 void set_backend_gateway_park_for_test(bool park) noexcept
279 {
280
2/2
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 4 taken 7 times.
10 safetyhook::set_route_park_for_test(
281 park ? safetyhook::RouteParkStage::AT_ENTRY : safetyhook::RouteParkStage::NONE
282 );
283 10 }
284
285 9 bool backend_gateway_park_reached_for_test() noexcept
286 {
287 9 return safetyhook::route_park_reached_for_test();
288 }
289
290 BackendIdleRefusal
291 325 backend_idle_refusal_for_test(void *begin, void *end, const void *site_base, std::uint8_t site_offset) noexcept
292 {
293 const std::array<safetyhook::AddressRange, 1> ranges{{{
294 static_cast<std::uint8_t *>(begin),
295 static_cast<std::uint8_t *>(end),
296 325 }}};
297 325 safetyhook::ReturnSites sites{};
298 325 sites.code = static_cast<const std::uint8_t *>(site_base);
299 325 sites.offsets[0] = site_offset;
300
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 323 times.
325 sites.count = site_base != nullptr ? 1 : 0;
301 325 const std::array<const safetyhook::ReturnSites *, 1> lists{&sites};
302 325 BackendIdleRefusal result{};
303 325 safetyhook::IdleRefusal refusal{};
304 try
305 {
306 const std::expected<bool, safetyhook::OsError> idle =
307
1/2
✓ Branch 8 → 9 taken 325 times.
✗ Branch 8 → 21 not taken.
325 safetyhook::threads_idle_outside(ranges, lists, &refusal);
308
3/4
✓ Branch 10 → 11 taken 325 times.
✗ Branch 10 → 14 not taken.
✓ Branch 12 → 13 taken 323 times.
✓ Branch 12 → 14 taken 2 times.
325 result.idle = idle.has_value() && *idle;
309 }
310 ✗ catch (...)
311 {
312 ✗ return result;
313 ✗ }
314 325 result.thread_id = refusal.thread_id;
315 325 const IdleRefusalSentence sentence = describe_idle_refusal(refusal);
316 325 std::ranges::copy(sentence.view(), result.sentence.begin());
317 325 result.sentence_size = sentence.size;
318 325 return result;
319 }
320
321 1 void retire_backend_trap_runtime_for_test() noexcept
322 {
323 1 safetyhook::retire_trap_runtime_for_test();
324 1 }
325
326 17 TrapTransactionOutcome drive_backend_trap_transaction_for_test(
327 void *from,
328 void *to,
329 std::size_t len,
330 const std::function<void()> &run_fn
331 ) noexcept
332 {
333 try
334 {
335 17 safetyhook::reset_trap_restore_trace_for_test();
336
2/2
✓ Branch 3 → 4 taken 16 times.
✓ Branch 3 → 11 taken 1 time.
17 const std::expected<void, safetyhook::OsError> result = safetyhook::trap_threads(
337 static_cast<std::uint8_t *>(from),
338 static_cast<std::uint8_t *>(to),
339 len,
340 run_fn
341 );
342
2/2
✓ Branch 5 → 6 taken 11 times.
✓ Branch 5 → 7 taken 5 times.
16 return result ? TrapTransactionOutcome::Restored : TrapTransactionOutcome::ReportedFailure;
343 }
344 1 catch (...)
345 {
346 1 return TrapTransactionOutcome::Threw;
347 1 }
348 }
349
350 12 void set_backend_trap_change_failure_target_for_test(void *segment_address) noexcept
351 {
352 12 safetyhook::g_trap_change_failure_override.store(
353 static_cast<std::uint8_t *>(segment_address),
354 std::memory_order_release
355 );
356 12 }
357
358 12 void set_backend_trap_segment_restore_failure_target_for_test(void *segment_address) noexcept
359 {
360 12 safetyhook::g_trap_segment_restore_failure_override.store(
361 static_cast<std::uint8_t *>(segment_address),
362 std::memory_order_release
363 );
364 12 }
365
366 2 std::size_t backend_trap_restore_trace_size_for_test() noexcept
367 {
368 2 return safetyhook::trap_restore_trace_size_for_test();
369 }
370
371 5 void *backend_trap_restore_trace_address_for_test(std::size_t index) noexcept
372 {
373 5 return safetyhook::trap_restore_trace_address_for_test(index);
374 }
375
376 14 void reset_backend_instruction_flush_trace_for_test() noexcept
377 {
378 14 safetyhook::reset_instruction_cache_flush_trace_for_test();
379 14 }
380
381 9 void set_backend_instruction_flush_failure_call_for_test(std::size_t call) noexcept
382 {
383 safetyhook::g_instruction_cache_flush_failure_call.store(call, std::memory_order_release);
384 9 }
385
386 14 std::size_t backend_instruction_flush_trace_size_for_test() noexcept
387 {
388 14 return safetyhook::instruction_cache_flush_trace_size_for_test();
389 }
390
391 29 BackendInstructionFlushObservation backend_instruction_flush_trace_for_test(std::size_t index) noexcept
392 {
393 const safetyhook::InstructionCacheFlushObservation observation =
394 29 safetyhook::instruction_cache_flush_trace_for_test(index);
395 return BackendInstructionFlushObservation{
396 29 .address = observation.address,
397 29 .size = observation.size,
398 29 .protect_calls_before = observation.protect_calls_before,
399 29 .succeeded = observation.succeeded,
400 29 };
401 }
402
403 23 void force_backend_ff_hook_for_test(bool force) noexcept
404 {
405 23 safetyhook::force_ff_hook_for_test(force);
406 23 }
407
408 1 std::size_t backend_instruction_boundary_trace_size_for_test() noexcept
409 {
410 1 return safetyhook::instruction_boundary_trace_size_for_test();
411 }
412
413 3 std::array<std::size_t, 2> backend_instruction_boundary_trace_for_test(std::size_t index) noexcept
414 {
415 3 const safetyhook::InstructionBoundary boundary = safetyhook::instruction_boundary_trace_for_test(index);
416 return {
417 3 boundary.original_offset,
418 3 boundary.trampoline_offset,
419 3 };
420 }
421
422 5 std::uint8_t backend_last_inline_error_type_for_test() noexcept
423 {
424 5 return safetyhook::last_inline_hook_error_type_for_test();
425 }
426
427 2 void *backend_non_executable_transaction_marker_for_test() noexcept
428 {
429 2 return safetyhook::non_executable_transaction_marker_for_test();
430 }
431
432 2 void omit_backend_relay_cell_for_test(bool omit) noexcept
433 {
434 2 safetyhook::omit_relay_cell_for_test(omit);
435 2 }
436
437 28 void set_backend_coordinator_refusal_for_test(unsigned refusal) noexcept
438 {
439 safetyhook::g_coordinator_refusal_for_test.store(refusal);
440 28 }
441
442 6311 BackendCoordinatorCounts backend_coordinator_counts_for_test() noexcept
443 {
444 6311 const safetyhook::ProcessCoordinatorSnapshot snapshot = safetyhook::process_coordinator_snapshot_for_test();
445 return BackendCoordinatorCounts{
446 6311 .live = snapshot.live,
447 6311 .retained = snapshot.retained,
448 6311 .vacant = snapshot.vacant,
449 6311 .free = snapshot.bytes == 0 ? 0 : safetyhook::PROCESS_ROUTE_CAPACITY - snapshot.live - snapshot.retained,
450
1/2
✓ Branch 3 → 4 taken 6311 times.
✗ Branch 3 → 5 not taken.
12622 };
451 }
452
453 struct BackendProbe
454 {
455 std::variant<safetyhook::InlineHook, safetyhook::MidHook> backend;
456 };
457
458 355 BackendProbe *create_backend_probe_for_test(
459 BackendProbeKind kind,
460 void *target,
461 void *destination,
462 std::string_view position_name
463 ) noexcept
464 {
465 try
466 {
467 355 const std::shared_ptr<safetyhook::Allocator> &allocator = hook::backend_allocator();
468 355 const safetyhook::PositionClaim claim = safetyhook::PositionClaim::from_name(position_name);
469
2/2
✓ Branch 4 → 5 taken 13 times.
✓ Branch 4 → 20 taken 342 times.
355 if (kind == BackendProbeKind::Mid)
470 {
471 auto created = safetyhook::MidHook::create(
472 allocator,
473 target,
474 reinterpret_cast<safetyhook::MidHookFn>(destination),
475 safetyhook::MidHook::StartDisabled,
476 claim
477
1/2
✓ Branch 5 → 6 taken 13 times.
✗ Branch 5 → 45 not taken.
13 );
478
4/12
✓ Branch 7 → 8 taken 13 times.
✗ Branch 7 → 14 not taken.
✓ Branch 8 → 9 taken 13 times.
✗ Branch 8 → 39 not taken.
✓ Branch 15 → 16 taken 13 times.
✗ Branch 15 → 18 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 13 times.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 42 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 42 not taken.
26 return created ? new BackendProbe{std::move(*created)} : nullptr;
479 13 }
480
2/2
✓ Branch 20 → 21 taken 14 times.
✓ Branch 20 → 22 taken 328 times.
342 const auto flags = static_cast<safetyhook::InlineHook::Flags>(
481 safetyhook::InlineHook::StartDisabled |
482 (kind == BackendProbeKind::Routed ? safetyhook::InlineHook::RoutedExternal : 0)
483 );
484
1/2
✓ Branch 23 → 24 taken 342 times.
✗ Branch 23 → 52 not taken.
342 auto created = safetyhook::InlineHook::create(allocator, target, destination, flags, claim);
485
4/12
✓ Branch 25 → 26 taken 342 times.
✗ Branch 25 → 32 not taken.
✓ Branch 26 → 27 taken 342 times.
✗ Branch 26 → 46 not taken.
✓ Branch 33 → 34 taken 342 times.
✗ Branch 33 → 36 not taken.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 36 taken 342 times.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 49 not taken.
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 49 not taken.
684 return created ? new BackendProbe{std::move(*created)} : nullptr;
486 342 }
487 ✗ catch (...)
488 {
489 ✗ return nullptr;
490 ✗ }
491 }
492
493 100653 bool drive_backend_probe_for_test(BackendProbe *probe, BackendProbeOperation operation) noexcept
494 {
495 100653 return backend_value_or(
496 100653 probe->backend,
497 false,
498 301959 [operation](auto &backend) noexcept -> bool
499 {
500 using Backend = std::remove_reference_t<decltype(backend)>;
501
17/20
bool DetourModKit::detail::drive_backend_probe_for_test(DetourModKit::detail::BackendProbe*, DetourModKit::detail::BackendProbeOperation)::{lambda(auto:1&)#1}::operator()<safetyhook::InlineHook>(safetyhook::InlineHook&) const:
✓ Branch 2 → 3 taken 303 times.
✓ Branch 2 → 4 taken 278 times.
✓ Branch 2 → 5 taken 50018 times.
✓ Branch 2 → 6 taken 50003 times.
✓ Branch 2 → 7 taken 16 times.
✓ Branch 2 → 8 taken 2 times.
✓ Branch 2 → 10 taken 2 times.
✓ Branch 2 → 14 taken 3 times.
✗ Branch 2 → 16 not taken.
✗ Branch 2 → 18 not taken.
bool DetourModKit::detail::drive_backend_probe_for_test(DetourModKit::detail::BackendProbe*, DetourModKit::detail::BackendProbeOperation)::{lambda(auto:1&)#1}::operator()<safetyhook::MidHook>(safetyhook::MidHook&) const:
✓ Branch 2 → 3 taken 10 times.
✓ Branch 2 → 4 taken 3 times.
✓ Branch 2 → 5 taken 5 times.
✓ Branch 2 → 6 taken 1 time.
✓ Branch 2 → 7 taken 2 times.
✓ Branch 2 → 8 taken 3 times.
✓ Branch 2 → 10 taken 1 time.
✓ Branch 2 → 14 taken 1 time.
✓ Branch 2 → 16 taken 2 times.
✗ Branch 2 → 18 not taken.
100653 switch (operation)
502 {
503 313 case BackendProbeOperation::Enable:
504 313 return try_backend_enable(backend);
505 281 case BackendProbeOperation::Disable:
506 281 return try_backend_disable(backend);
507 50023 case BackendProbeOperation::Bypass:
508 50023 return backend.bypass();
509 50004 case BackendProbeOperation::Resume:
510 50004 return backend.resume();
511 18 case BackendProbeOperation::Vacate:
512 18 return backend.vacate();
513 5 case BackendProbeOperation::Reset:
514 5 backend.reset();
515 5 return true;
516 3 case BackendProbeOperation::MoveAssign:
517 3 backend = Backend{};
518 3 return true;
519 4 case BackendProbeOperation::RetainRoute:
520 4 backend.retain_route();
521 4 return true;
522 2 case BackendProbeOperation::ObserveRouteEntries:
523 2 return backend.observe_route_entries() == 0;
524 }
525 ✗ return false;
526 }
527 100653 );
528 }
529
530 365 BackendProbeState backend_probe_state_for_test(const BackendProbe *probe) noexcept
531 {
532 365 return backend_value_or(
533 365 probe->backend,
534 BackendProbeState{},
535 730 [](const auto &backend) noexcept
536 {
537 365 bool stub_freed = false;
538 if constexpr (std::is_same_v<std::remove_cvref_t<decltype(backend)>, safetyhook::MidHook>)
539 {
540 16 stub_freed = backend.stub_freed();
541 }
542 return BackendProbeState{
543 365 .valid = static_cast<bool>(backend),
544 365 .enabled = backend.enabled(),
545 365 .claimed = backend.claimed(),
546 365 .bypassed = backend.bypassed(),
547 365 .trampoline = backend.trampoline().data(),
548 365 .relay_slot = backend.relay_slot_for_test(),
549 365 .relay_cell = backend.relay_cell_for_test(),
550 365 .route_retained = backend.route_retained(),
551 .stub_freed = stub_freed,
552 365 .retention_reason = backend.route_retention_reason(),
553 730 };
554 }
555 365 );
556 }
557
558 355 void destroy_backend_probe_for_test(BackendProbe *probe) noexcept
559 {
560
1/2
✓ Branch 2 → 3 taken 355 times.
✗ Branch 2 → 5 not taken.
355 delete probe;
561 355 }
562
563 namespace
564 {
565 // One-byte targets for the filler records. Their patches overlap no hook target, so they change no layer
566 // count and no top() answer.
567 std::array<std::uint8_t, safetyhook::PROCESS_ROUTE_CAPACITY> s_coordinator_fill_keys{};
568 std::size_t s_coordinator_fill_count{0};
569 } // namespace
570
571 5 std::size_t fill_backend_coordinator_for_test(std::size_t count) noexcept
572 {
573 5 safetyhook::ProcessCoordinator coordinator;
574 5 std::size_t added = 0;
575
6/8
✓ Branch 10 → 11 taken 2238 times.
✗ Branch 10 → 16 not taken.
✓ Branch 11 → 12 taken 2233 times.
✓ Branch 11 → 16 taken 5 times.
✓ Branch 14 → 15 taken 2233 times.
✗ Branch 14 → 16 not taken.
✓ Branch 17 → 4 taken 2233 times.
✓ Branch 17 → 18 taken 5 times.
4471 while (coordinator && added < count && s_coordinator_fill_count < s_coordinator_fill_keys.size())
576 {
577 2233 std::uint8_t *const key = &s_coordinator_fill_keys[s_coordinator_fill_count];
578
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2233 times.
2233 if (!coordinator.add(key, 1, {key, key + 1}, {}, nullptr, {}))
579 {
580 ✗ break;
581 }
582 2233 ++s_coordinator_fill_count;
583 2233 ++added;
584 }
585 10 return added;
586 5 }
587
588 9 void clear_backend_coordinator_fill_for_test() noexcept
589 {
590 9 safetyhook::ProcessCoordinator coordinator;
591
2/2
✓ Branch 6 → 4 taken 2233 times.
✓ Branch 6 → 7 taken 9 times.
2242 while (s_coordinator_fill_count != 0)
592 {
593 2233 coordinator.remove(&s_coordinator_fill_keys[--s_coordinator_fill_count]);
594 }
595 9 }
596 #endif
597 } // namespace DetourModKit::detail
598
599 namespace DetourModKit
600 {
601 // File-local helpers live at DetourModKit scope, outside namespace hook. A bare `detail::` therefore resolves to
602 // DetourModKit::detail, the memory/x86/platform engine. A hook::detail subnamespace otherwise shadows it and
603 // breaks the unqualified lookup.
604 namespace
605 {
606 /**
607 * @brief Takes a counted reference on this module for an install path and honors the test override.
608 * @details On failure the primitive restores the thread's last-error, so the caller can read GetLastError()
609 * immediately after a null return.
610 */
611 17090 [[nodiscard]] HMODULE acquire_hook_self_ref() noexcept
612 {
613 #if defined(DMK_ENABLE_TEST_SEAMS)
614
2/2
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 4 taken 17086 times.
17090 if (auto *override_fn = DetourModKit::detail::g_hook_module_ref_override)
615 {
616 4 return override_fn();
617 }
618 #endif
619 17086 return DetourModKit::detail::acquire_module_ref(diagnostics::ModulePinReason::Hook);
620 }
621
622 /// Names the chain position that a request with @p name claims and leaves behind (`[B-105]`).
623 16908 [[nodiscard]] safetyhook::PositionClaim position_claim_for(std::string_view name) noexcept
624 {
625 #if defined(DMK_ENABLE_TEST_SEAMS)
626
2/2
✓ Branch 3 → 4 taken 17 times.
✓ Branch 3 → 5 taken 16891 times.
16908 if (DetourModKit::detail::g_hook_position_claims_refused_for_test.load(std::memory_order_acquire))
627 {
628 17 return {};
629 }
630 #endif
631 16891 return safetyhook::PositionClaim::from_name(name);
632 }
633
634 /// Logs that an install took the vacated position of an earlier generation.
635 704 void note_position_claim(std::string_view name, std::uintptr_t target) noexcept
636 {
637 704 (void)log().try_log(
638 LogLevel::Info,
639 "hook: '{}' at 0x{:0{}X} claimed a vacated position.",
640 name,
641 target,
642 704 sizeof(std::uintptr_t) * 2
643 );
644 704 }
645 /// Reports whether the foreign-inline-hook preflight found a present redirect and its destination.
646 enum class PrehookState : std::uint8_t
647 {
648 NotHooked,
649 HookedBySameModule,
650 HookedByOtherModule
651 };
652
653 struct PrehookDetection
654 {
655 PrehookState state{PrehookState::NotHooked};
656 std::uintptr_t jmp_destination{0};
657 };
658
659 /// Releases a module reference automatically unless ownership is handed to a hook Impl.
660 class ModuleRefGuard
661 {
662 public:
663 17087 explicit ModuleRefGuard(HMODULE module) noexcept : m_module(module) {}
664
665 17087 ~ModuleRefGuard() noexcept { detail::release_module_ref(m_module, diagnostics::ModulePinReason::Hook); }
666
667 ModuleRefGuard(const ModuleRefGuard &) = delete;
668 ModuleRefGuard &operator=(const ModuleRefGuard &) = delete;
669 ModuleRefGuard(ModuleRefGuard &&) = delete;
670 ModuleRefGuard &operator=(ModuleRefGuard &&) = delete;
671
672 16937 [[nodiscard]] HMODULE release() noexcept { return std::exchange(m_module, nullptr); }
673
674 145 [[nodiscard]] HMODULE get() const noexcept { return m_module; }
675
676 private:
677 HMODULE m_module{nullptr};
678 };
679
680 /// Returns a claimed mid-adapter slot to the pool unless the install transaction commits it to an Impl.
681 class MidAdapterSlotGuard
682 {
683 public:
684 5268 explicit MidAdapterSlotGuard(std::size_t index) noexcept : m_index(index) {}
685
686 // The guard is safe without a rundown because it fires only before hook arm. No adapter entry occurred.
687 // Once the Impl owns the slot, teardown runs its rundown instead.
688 5268 ~MidAdapterSlotGuard() noexcept { detail::release_mid_adapter_slot(m_index); }
689
690 MidAdapterSlotGuard(const MidAdapterSlotGuard &) = delete;
691 MidAdapterSlotGuard &operator=(const MidAdapterSlotGuard &) = delete;
692 MidAdapterSlotGuard(MidAdapterSlotGuard &&) = delete;
693 MidAdapterSlotGuard &operator=(MidAdapterSlotGuard &&) = delete;
694
695 5254 [[nodiscard]] std::size_t release() noexcept
696 {
697 5254 return std::exchange(m_index, detail::MID_ADAPTER_CAPACITY);
698 }
699
700 private:
701 std::size_t m_index{detail::MID_ADAPTER_CAPACITY};
702 };
703
704 /**
705 * @brief Decodes an initial inline-hook redirect at @p target_address and returns its destination.
706 * @details Recognizes three redirect shapes that a foreign hook plants over a prologue. These shapes are E9
707 * rel32, FF 25 [rip+disp32], and 48 B8 imm64 plus FF E0. Returns nullopt for any other prologue.
708 */
709 12639 std::optional<std::uintptr_t> decode_prehook_destination(std::uintptr_t target_address) noexcept
710 {
711 12639 std::array<std::uint8_t, 2> opcode{};
712
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 12639 times.
25278 if (!detail::guarded_read_bytes(target_address, opcode.data(), opcode.size()))
713 {
714 ✗ return std::nullopt;
715 }
716
717 // EB (jmp rel8) reaches at most +/-127 bytes. This range is too short to land in a foreign hook stub. An
718 // initial 0xEB is ordinary code and deliberately does not match.
719
2/2
✓ Branch 10 → 11 taken 3272 times.
✓ Branch 10 → 12 taken 9367 times.
12639 if (opcode[0] == 0xE9)
720 {
721 3272 return detail::decode_e9_rel32(target_address);
722 }
723
5/6
✓ Branch 13 → 14 taken 5 times.
✓ Branch 13 → 17 taken 9362 times.
✓ Branch 15 → 16 taken 5 times.
✗ Branch 15 → 17 not taken.
✓ Branch 18 → 19 taken 5 times.
✓ Branch 18 → 20 taken 9362 times.
9367 if (opcode[0] == 0xFF && opcode[1] == 0x25)
724 {
725 5 return detail::decode_ff25_indirect(target_address);
726 }
727
6/6
✓ Branch 21 → 22 taken 27 times.
✓ Branch 21 → 25 taken 9335 times.
✓ Branch 23 → 24 taken 16 times.
✓ Branch 23 → 25 taken 11 times.
✓ Branch 26 → 27 taken 16 times.
✓ Branch 26 → 28 taken 9346 times.
9362 if (opcode[0] == 0x48 && opcode[1] == 0xB8)
728 {
729 16 return detail::decode_mov_rax_imm64_jmp_rax(target_address);
730 }
731 9346 return std::nullopt;
732 }
733
734 /// Detects whether @p target_address is already inline-hooked and classifies the module that owns the redirect.
735 12639 PrehookDetection detect_existing_inline_hook(std::uintptr_t target_address) noexcept
736 {
737 12639 PrehookDetection result;
738
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 12639 times.
12639 if (target_address == 0)
739 {
740 ✗ return result;
741 }
742 12639 const auto destination_opt = decode_prehook_destination(target_address);
743
2/2
✓ Branch 6 → 7 taken 9346 times.
✓ Branch 6 → 8 taken 3293 times.
12639 if (!destination_opt)
744 {
745 9346 return result;
746 }
747 3293 const auto destination = *destination_opt;
748 3293 result.jmp_destination = destination;
749
750 3293 HMODULE target_module = nullptr;
751 3293 HMODULE dest_module = nullptr;
752
2/2
✓ Branch 10 → 11 taken 2033 times.
✓ Branch 10 → 12 taken 1260 times.
3293 if (!GetModuleHandleExW(
753 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
754 reinterpret_cast<LPCWSTR>(target_address),
755 &target_module
756 ))
757 {
758 2033 target_module = nullptr;
759 }
760
2/2
✓ Branch 13 → 14 taken 3275 times.
✓ Branch 13 → 15 taken 18 times.
3293 if (!GetModuleHandleExW(
761 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
762 reinterpret_cast<LPCWSTR>(destination),
763 &dest_module
764 ))
765 {
766 3275 dest_module = nullptr;
767 }
768
3/4
✓ Branch 15 → 16 taken 18 times.
✓ Branch 15 → 18 taken 3275 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 18 times.
3293 result.state = (dest_module != nullptr && target_module == dest_module) ? PrehookState::HookedBySameModule
769 : PrehookState::HookedByOtherModule;
770 3293 return result;
771 }
772
773 /// PrologueRisk classifies the target's first byte during inline or mid preflight.
774 enum class PrologueRisk : std::uint8_t
775 {
776 None,
777 // Prologue::Fail refuses a 0xCC int3 or 0xCD int n.
778 Breakpoint,
779 // Every policy refuses an unreadable first byte.
780 Unreadable
781 };
782
783 // An initial rel32 call is left to the backend, which relocates it or fails typed. An unreadable first byte
784 // stays a distinct fail-closed result because the target can change after window validation.
785 16911 PrologueRisk classify_prologue_risk(std::uintptr_t target_address) noexcept
786 {
787
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 16911 times.
16911 if (target_address == 0)
788 {
789 ✗ return PrologueRisk::None;
790 }
791 16911 std::uint8_t first_byte = 0;
792
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 16911 times.
16911 if (!detail::guarded_read_bytes(target_address, &first_byte, sizeof(first_byte)))
793 {
794 ✗ return PrologueRisk::Unreadable;
795 }
796
2/2
✓ Branch 7 → 8 taken 21 times.
✓ Branch 7 → 9 taken 16890 times.
16911 switch (first_byte)
797 {
798 21 case 0xCC:
799 case 0xCD:
800 21 return PrologueRisk::Breakpoint;
801 16890 default:
802 16890 return PrologueRisk::None;
803 }
804 }
805
806 /// Returns a human-readable fragment for a flagged prologue risk in diagnostic log lines.
807 7 [[nodiscard]] std::string_view prologue_risk_description(PrologueRisk risk) noexcept
808 {
809
1/4
✓ Branch 2 → 3 taken 7 times.
✗ Branch 2 → 4 not taken.
✗ Branch 2 → 5 not taken.
✗ Branch 2 → 6 not taken.
7 switch (risk)
810 {
811 7 case PrologueRisk::Breakpoint:
812 7 return "a breakpoint (0xCC/0xCD)";
813 ✗ case PrologueRisk::Unreadable:
814 ✗ return "an unreadable byte";
815 ✗ case PrologueRisk::None:
816 ✗ return "an unremarkable byte";
817 }
818 ✗ return "an unremarkable byte";
819 }
820
821 /// Names the allocator's verdict so a log line separates an exhausted window from a refused commit.
822 2 [[nodiscard]] std::string_view allocator_error_description(safetyhook::Allocator::Error error) noexcept
823 {
824
1/3
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
✗ Branch 2 → 5 not taken.
2 switch (error)
825 {
826 ✗ case safetyhook::Allocator::Error::BAD_VIRTUAL_ALLOC:
827 ✗ return "VirtualAlloc refused the request";
828 2 case safetyhook::Allocator::Error::NO_MEMORY_IN_RANGE:
829 2 return "no free region within +/-2 GB of the target";
830 }
831 ✗ return "an unlisted allocator verdict";
832 }
833
834 // These formatters preserve each backend reason in the diagnostic log after failures map to
835 // ErrorCode::BackendFailed.
836 10 std::string backend_error_string(const safetyhook::InlineHook::Error &err)
837 {
838 10 const int type_int = static_cast<int>(err.type);
839
1/2
✓ Branch 2 → 3 taken 10 times.
✗ Branch 2 → 53 not taken.
10 const auto ip_str = format::format_address(reinterpret_cast<std::uintptr_t>(err.ip));
840
5/14
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 7 not taken.
✗ Branch 3 → 9 not taken.
✗ Branch 3 → 11 not taken.
✓ Branch 3 → 13 taken 1 time.
✗ Branch 3 → 15 not taken.
✓ Branch 3 → 17 taken 1 time.
✗ Branch 3 → 19 not taken.
✗ Branch 3 → 21 not taken.
✓ Branch 3 → 23 taken 5 times.
✓ Branch 3 → 25 taken 1 time.
✗ Branch 3 → 27 not taken.
✗ Branch 3 → 29 not taken.
✗ Branch 3 → 31 not taken.
10 switch (err.type)
841 {
842 2 case safetyhook::InlineHook::Error::BAD_ALLOCATION:
843 return std::format(
844 "InlineHook backend error ({}): bad allocation ({})",
845 type_int,
846 2 allocator_error_description(err.allocator_error)
847
1/2
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 36 not taken.
2 );
848 ✗ case safetyhook::InlineHook::Error::FAILED_TO_DECODE_INSTRUCTION:
849 return std::format(
850 "InlineHook backend error ({}): failed to decode instruction at {}",
851 type_int,
852 ip_str
853
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 38 not taken.
✗ );
854 ✗ case safetyhook::InlineHook::Error::SHORT_JUMP_IN_TRAMPOLINE:
855
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 39 not taken.
✗ return std::format("InlineHook backend error ({}): short jump in trampoline at {}", type_int, ip_str);
856 ✗ case safetyhook::InlineHook::Error::IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE:
857 return std::format(
858 "InlineHook backend error ({}): IP-relative instruction out of range at {}",
859 type_int,
860 ip_str
861
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 40 not taken.
✗ );
862 1 case safetyhook::InlineHook::Error::UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE:
863 return std::format(
864 "InlineHook backend error ({}): unsupported instruction in trampoline at {}",
865 type_int,
866 ip_str
867
1/2
✓ Branch 13 → 14 taken 1 time.
✗ Branch 13 → 41 not taken.
1 );
868 ✗ case safetyhook::InlineHook::Error::FAILED_TO_UNPROTECT:
869
0/2
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 42 not taken.
✗ return std::format("InlineHook backend error ({}): failed to unprotect memory at {}", type_int, ip_str);
870 1 case safetyhook::InlineHook::Error::NOT_ENOUGH_SPACE:
871 return std::format(
872 "InlineHook backend error ({}): prologue too short for the hook at {}",
873 type_int,
874 ip_str
875
1/2
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 43 not taken.
1 );
876 ✗ case safetyhook::InlineHook::Error::FAILED_TO_REGISTER_UNWIND:
877 return std::format(
878 "InlineHook backend error ({}): the platform refused unwind metadata for the routed "
879 "wrapper at {}",
880 type_int,
881 ip_str
882
0/2
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 44 not taken.
✗ );
883 ✗ case safetyhook::InlineHook::Error::ROUTE_RETENTION_EXHAUSTED:
884 return std::format(
885 "InlineHook backend error ({}): the routed retention ceiling refused the permanent "
886 "chain for {}",
887 type_int,
888 ip_str
889
0/2
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 45 not taken.
✗ );
890 5 case safetyhook::InlineHook::Error::FAILED_TO_FLUSH_INSTRUCTION_CACHE:
891 return std::format(
892 "InlineHook backend error ({}): failed to flush the instruction cache at {}",
893 type_int,
894 ip_str
895
1/2
✓ Branch 23 → 24 taken 5 times.
✗ Branch 23 → 46 not taken.
5 );
896 1 case safetyhook::InlineHook::Error::COORDINATION_UNAVAILABLE:
897 return std::format(
898 "InlineHook backend error ({}): process coordination is unavailable at {}",
899 type_int,
900 ip_str
901
1/2
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 47 not taken.
1 );
902 ✗ case safetyhook::InlineHook::Error::LAYER_CONFLICT:
903 return std::format(
904 "InlineHook backend error ({}): a newer participant owns the target at {}",
905 type_int,
906 ip_str
907
0/2
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 48 not taken.
✗ );
908 ✗ case safetyhook::InlineHook::Error::NON_EXECUTABLE_TRANSACTION_UNAVAILABLE:
909 return std::format(
910 "InlineHook backend error ({}): a non-executable patch transaction is unavailable at {}",
911 type_int,
912 ip_str
913
0/2
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 49 not taken.
✗ );
914 ✗ default:
915
0/2
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 50 not taken.
✗ return std::format("InlineHook backend error ({}): unknown error type", type_int);
916 }
917 10 }
918
919 8 std::string backend_error_string(const safetyhook::MidHook::Error &err)
920 {
921 8 const int type_int = static_cast<int>(err.type);
922
1/3
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 8 times.
✗ Branch 2 → 10 not taken.
8 switch (err.type)
923 {
924 ✗ case safetyhook::MidHook::Error::BAD_ALLOCATION:
925 return std::format(
926 "MidHook backend error ({}): bad allocation ({})",
927 type_int,
928 ✗ allocator_error_description(err.allocator_error)
929
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 14 not taken.
✗ );
930 8 case safetyhook::MidHook::Error::BAD_INLINE_HOOK:
931 return std::format(
932 "MidHook backend error ({}): bad underlying inline hook. {}",
933 type_int,
934
1/2
✓ Branch 6 → 7 taken 8 times.
✗ Branch 6 → 19 not taken.
16 backend_error_string(err.inline_hook_error)
935
1/2
✓ Branch 7 → 8 taken 8 times.
✗ Branch 7 → 16 not taken.
8 );
936 ✗ default:
937
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 20 not taken.
✗ return std::format("MidHook backend error ({}): unknown error type", type_int);
938 }
939 }
940
941 /**
942 * @brief Serializes VMT object-vptr transitions.
943 * @details A namespace-scope VmtHook can outlive ordinary hook statics. The mutex uses never-destroyed
944 * storage (`[B-47]`).
945 */
946 296 [[nodiscard]] std::mutex &vmt_object_mutex() noexcept
947 {
948 alignas(std::mutex) static unsigned char storage[sizeof(std::mutex)];
949
4/6
✓ Branch 2 → 3 taken 62 times.
✓ Branch 2 → 10 taken 234 times.
✓ Branch 4 → 5 taken 62 times.
✗ Branch 4 → 10 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 62 times.
296 static std::mutex *const gate = ::new (static_cast<void *>(storage)) std::mutex();
950 296 return *gate;
951 }
952
953 /**
954 * @brief Acquires the VMT object gate and returns an unowned lock if the OS mutex acquisition fails.
955 * @details Callers fail closed on an unowned lock. A restore without the gate races another object-vptr
956 * transition.
957 */
958 296 [[nodiscard]] std::unique_lock<std::mutex> acquire_vmt_object_lock() noexcept
959 {
960 try
961 {
962
1/2
✓ Branch 3 → 4 taken 296 times.
✗ Branch 3 → 6 not taken.
296 return std::unique_lock<std::mutex>(vmt_object_mutex());
963 }
964 ✗ catch (...)
965 {
966 ✗ return std::unique_lock<std::mutex>{};
967 ✗ }
968 }
969
970 // Decides whether @p slot_value, the first qword of a vtable slot, resembles a callable function body. A 0x00
971 // first byte marks an uninitialized page. Bytes 0xCC/0xCD are int3/int padding. Bytes 0xC2/0xC3 are bare RETs.
972 // An EB/E9 same-module jump is a stub, such as an incremental-link ILT entry or a patched slot. Its clone makes
973 // the new "original" a forwarder. MSVC adjustor thunks start with byte 0x48 and pass. Tail calls to a foreign
974 // module pass. The reads use fault guards.
975 5 bool looks_like_function_vmt_slot(std::uintptr_t slot_value) noexcept
976 {
977
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 5 times.
5 if (slot_value == 0)
978 {
979 ✗ return false;
980 }
981 5 std::uint8_t first_byte = 0;
982
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 5 times.
5 if (!detail::guarded_read_bytes(slot_value, &first_byte, sizeof(first_byte)))
983 {
984 ✗ return false;
985 }
986
2/2
✓ Branch 7 → 8 taken 3 times.
✓ Branch 7 → 9 taken 2 times.
5 switch (first_byte)
987 {
988 3 case 0x00:
989 case 0xCC:
990 case 0xCD:
991 case 0xC2:
992 case 0xC3:
993 3 return false;
994 2 default:
995 2 break;
996 }
997
998
3/4
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 12 not taken.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 29 taken 1 time.
2 if (first_byte == 0xEB || first_byte == 0xE9)
999 {
1000 1 HMODULE slot_module = nullptr;
1001 1 HMODULE jmp_module = nullptr;
1002 1 if (GetModuleHandleExW(
1003 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
1004 reinterpret_cast<LPCWSTR>(slot_value),
1005 &slot_module
1006
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 1 time.
1 ) == 0)
1007 {
1008 1 return false;
1009 }
1010 const std::optional<std::uintptr_t> jmp_target =
1011
1/2
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 17 not taken.
1 (first_byte == 0xE9) ? detail::decode_e9_rel32(slot_value) : detail::decode_eb_rel8(slot_value);
1012
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 1 time.
1 if (!jmp_target)
1013 {
1014 ✗ return false;
1015 }
1016 2 if (GetModuleHandleExW(
1017 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
1018 1 reinterpret_cast<LPCWSTR>(*jmp_target),
1019 &jmp_module
1020
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 1 time.
1 ) == 0)
1021 {
1022 ✗ return false;
1023 }
1024
1/2
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 27 not taken.
1 if (slot_module == jmp_module)
1025 {
1026 1 return false;
1027 }
1028 }
1029 1 return true;
1030 }
1031
1032 // SafetyHook sizes a clone through an executable check for each slot target. This module-owned code address
1033 // fixes that answer after DMK counts the captured words. The detached clone receives the captured function
1034 // pointers before any host object can observe it.
1035 ✗ void vmt_snapshot_executable_marker() noexcept {}
1036
1037 /**
1038 * @brief Counts callable slots from the object's current vptr, guarded and capped at
1039 * @ref detail::MAX_VMT_SLOTS.
1040 * @note The result bounds the guarded capture in @ref clone_vmt_snapshot. It is not the clone's slot count:
1041 * the backend derives that from the captured snapshot, which is the only bound a slot write respects.
1042 */
1043 122 [[nodiscard]] std::optional<std::size_t> count_vmt_method_slots(std::uintptr_t vptr) noexcept
1044 {
1045 122 std::size_t count = 0;
1046 for (;;)
1047 {
1048
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 4657 times.
4658 if (count >= detail::MAX_VMT_SLOTS)
1049 {
1050 122 return std::nullopt;
1051 }
1052
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 4657 times.
4657 if (count > (std::numeric_limits<std::uintptr_t>::max() - vptr) / sizeof(std::uintptr_t))
1053 {
1054 ✗ return std::nullopt;
1055 }
1056
1057 4657 const std::uintptr_t slot_address = vptr + (count * sizeof(std::uintptr_t));
1058 4657 const std::optional<std::uintptr_t> slot = detail::guarded_read<std::uintptr_t>(slot_address);
1059
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 4657 times.
4657 if (!slot)
1060 {
1061 ✗ return std::nullopt;
1062 }
1063 // detail::is_executable_address classifies the slot from VirtualQuery page state alone (B-66): the
1064 // backend's executable query parses the owning module's PE headers unguarded and faults the host
1065 // when that header page is unreadable. Lifecycle.VmtUnreadableModuleHeader pins the contract.
1066
2/2
✓ Branch 14 → 15 taken 121 times.
✓ Branch 14 → 16 taken 4536 times.
4657 if (!detail::is_executable_address(*slot))
1067 {
1068 121 return count;
1069 }
1070 4536 ++count;
1071 4536 }
1072 }
1073
1074 /**
1075 * @struct DetachedVmtBackend
1076 * @brief Stores a backend clone that no host object points at yet and the facts its publisher needs.
1077 * @details method_count matches the clone the backend allocated, not the caller's pre-count. It is the only
1078 * bound between a caller's index and an unchecked slot write.
1079 */
1080 struct DetachedVmtBackend
1081 {
1082 safetyhook::VmtHook backend;
1083 std::uintptr_t cloned_vptr_base{0};
1084 std::size_t method_count{0};
1085 };
1086
1087 /**
1088 * @brief Clones an owned, count-normalized vtable snapshot. The backend remains unattached to any object.
1089 * @return The detached backend, InvalidObject on a bad prefix/capture/empty table, or BackendFailed.
1090 */
1091 120 [[nodiscard]] Result<DetachedVmtBackend> clone_vmt_snapshot(std::uintptr_t vptr, std::size_t slot_budget)
1092 {
1093 120 constexpr std::size_t header_count = safetyhook::VMT_HEADER;
1094 120 constexpr std::uintptr_t header_bytes = header_count * sizeof(std::uintptr_t);
1095
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 120 times.
120 if (vptr < header_bytes)
1096 {
1097 ✗ return std::unexpected(Error{ErrorCode::InvalidObject, "hook::vmt_for", vptr});
1098 }
1099
1100 // The final zero is a private non-executable sentinel for the backend slot walk.
1101
2/2
✓ Branch 8 → 9 taken 118 times.
✓ Branch 8 → 88 taken 2 times.
122 std::vector<std::uintptr_t> snapshot(header_count + slot_budget + 1, 0);
1102 118 const std::uintptr_t snapshot_source = vptr - header_bytes;
1103 118 const std::size_t snapshot_bytes = (header_count + slot_budget) * sizeof(std::uintptr_t);
1104
2/2
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 16 taken 117 times.
118 if (!detail::guarded_read_bytes(snapshot_source, snapshot.data(), snapshot_bytes))
1105 {
1106 1 return std::unexpected(Error{ErrorCode::InvalidObject, "hook::vmt_for", snapshot_source});
1107 }
1108
1109 // Walk the captured words again rather than trust slot_budget. The budget came from foreign memory a
1110 // moment earlier. The backend sizes its clone from THIS buffer. The two can disagree if the vtable changes
1111 // between those steps. The backend bounds-checks no slot write, and hook_method admits any index below the
1112 // count published here. A count for slots absent from the clone therefore causes an out-of-bounds write.
1113 117 std::size_t cloned_slots = 0;
1114 // Page-state classification only; see count_vmt_method_slots (B-66).
1115
6/6
✓ Branch 18 → 19 taken 430 times.
✓ Branch 18 → 23 taken 115 times.
✓ Branch 21 → 22 taken 428 times.
✓ Branch 21 → 23 taken 2 times.
✓ Branch 24 → 17 taken 428 times.
✓ Branch 24 → 25 taken 117 times.
545 while (cloned_slots < slot_budget && detail::is_executable_address(snapshot[header_count + cloned_slots]))
1116 {
1117 428 ++cloned_slots;
1118 }
1119
1/2
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 29 taken 117 times.
117 if (cloned_slots == 0)
1120 {
1121 ✗ return std::unexpected(Error{ErrorCode::InvalidObject, "hook::vmt_for", vptr});
1122 }
1123 // Terminate the counted run so no later step can reach past it.
1124 117 snapshot[header_count + cloned_slots] = 0;
1125
1126 // The captured pointer words are stable, but the execute protections of the pages they name are not. If a
1127 // target loses execute permission between the walk above and SafetyHook's walk, the backend can allocate
1128 // fewer slots than method_count permits. Give the backend an equally-sized run of a module-owned marker,
1129 // then restore the captured pointers into its detached clone before publication.
1130
2/2
✓ Branch 30 → 31 taken 116 times.
✓ Branch 30 → 104 taken 1 time.
117 std::vector<std::uintptr_t> backend_snapshot = snapshot;
1131 116 const std::uintptr_t executable_marker = reinterpret_cast<std::uintptr_t>(&vmt_snapshot_executable_marker);
1132 116 std::fill_n(
1133 116 backend_snapshot.begin() + static_cast<std::ptrdiff_t>(header_count),
1134 cloned_slots,
1135 executable_marker
1136 );
1137 #if defined(DMK_ENABLE_TEST_SEAMS)
1138
2/2
✓ Branch 58 → 59 taken 1 time.
✓ Branch 58 → 60 taken 115 times.
116 if (auto *probe = DetourModKit::detail::g_vmt_before_backend_clone_probe)
1139 {
1140 1 probe();
1141 }
1142 #endif
1143 116 auto *surrogate_vptr = reinterpret_cast<std::uint8_t **>(backend_snapshot.data() + header_count);
1144
2/2
✓ Branch 61 → 62 taken 112 times.
✓ Branch 61 → 102 taken 4 times.
116 auto created = safetyhook::VmtHook::create(static_cast<void *>(&surrogate_vptr));
1145
1/2
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 67 taken 112 times.
112 if (!created)
1146 {
1147 ✗ return std::unexpected(Error{ErrorCode::BackendFailed, "hook::vmt_for", vptr});
1148 }
1149
1150
2/4
✓ Branch 67 → 68 taken 112 times.
✗ Branch 67 → 100 not taken.
✓ Branch 70 → 71 taken 112 times.
✗ Branch 70 → 100 not taken.
224 safetyhook::VmtHook backend = std::move(created.value());
1151 112 const std::uintptr_t cloned_vptr_base = reinterpret_cast<std::uintptr_t>(surrogate_vptr);
1152
1/2
✓ Branch 72 → 73 taken 112 times.
✗ Branch 72 → 98 not taken.
112 std::copy_n(
1153 112 snapshot.data() + header_count,
1154 cloned_slots,
1155 reinterpret_cast<std::uintptr_t *>(cloned_vptr_base)
1156 );
1157 // Erase the stack surrogate from the backend before it leaves scope. Real host objects are published and
1158 // restored only through DMK's guarded swaps, so the backend never retains a foreign object pointer.
1159
1/2
✓ Branch 73 → 74 taken 112 times.
✗ Branch 73 → 98 not taken.
112 backend.remove(static_cast<void *>(&surrogate_vptr));
1160
3/8
✓ Branch 76 → 77 taken 112 times.
✗ Branch 76 → 97 not taken.
✓ Branch 77 → 78 taken 112 times.
✗ Branch 77 → 92 not taken.
✗ Branch 80 → 81 not taken.
✓ Branch 80 → 82 taken 112 times.
✗ Branch 94 → 95 not taken.
✗ Branch 94 → 96 not taken.
112 return DetachedVmtBackend{std::move(backend), cloned_vptr_base, cloned_slots};
1161 122 }
1162
1163 [[nodiscard]] bool
1164 228 publish_vmt_object_word(void *object, std::uintptr_t expected, std::uintptr_t replacement) noexcept
1165 {
1166 #if defined(DMK_ENABLE_TEST_SEAMS)
1167
2/2
✓ Branch 2 → 3 taken 6 times.
✓ Branch 2 → 4 taken 222 times.
228 if (auto *probe = DetourModKit::detail::g_vmt_before_publish_probe)
1168 {
1169 6 probe(object);
1170 }
1171 #endif
1172 228 return detail::guarded_compare_exchange_word(
1173 reinterpret_cast<std::uintptr_t>(object),
1174 expected,
1175 replacement
1176 228 );
1177 }
1178
1179 /// Resolves a hook Target to an absolute address, through scan::resolve for a deferred OwnedScanRequest.
1180 16989 Result<std::uintptr_t> resolve_target(const hook::Target &target) noexcept
1181 {
1182
2/2
✓ Branch 3 → 4 taken 16978 times.
✓ Branch 3 → 7 taken 11 times.
16989 if (const Address *absolute = std::get_if<Address>(&target))
1183 {
1184 16978 return absolute->raw();
1185 }
1186 11 const auto *request = std::get_if<scan::OwnedScanRequest>(&target);
1187
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 12 taken 11 times.
11 if (request == nullptr)
1188 {
1189 ✗ return std::unexpected(Error{ErrorCode::InvalidTargetAddress, "hook::resolve_target"});
1190 }
1191 // scan::resolve can allocate and throw. This helper is noexcept, so it contains the exception and reports
1192 // an Error instead of host termination.
1193 try
1194 {
1195
1/2
✓ Branch 13 → 14 taken 11 times.
✗ Branch 13 → 27 not taken.
11 Result<scan::Hit> hit = scan::resolve(request->view());
1196
2/2
✓ Branch 15 → 16 taken 3 times.
✓ Branch 15 → 20 taken 8 times.
11 if (!hit)
1197 {
1198 3 return std::unexpected(hit.error());
1199 }
1200 8 return hit->address.raw();
1201 11 }
1202
0/2
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 34 not taken.
✗ catch (const std::bad_alloc &)
1203 {
1204 ✗ return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::resolve_target"});
1205 ✗ }
1206 ✗ catch (...)
1207 {
1208 ✗ return std::unexpected(Error{ErrorCode::Unknown, "hook::resolve_target"});
1209 ✗ }
1210 }
1211
1212 /**
1213 * @brief Resolves @p target and reserves it in the HookLedger. Reads no target byte.
1214 * @return The reserved target, or the Error that fails the install with nothing reserved.
1215 * @details Waits until the reservation is first in the target queue, so backend patches for one target
1216 * follow creation order. On success, the caller owns the reservation. Commit it before handle
1217 * publication, or roll it back through HookLedger::release_hook.
1218 */
1219 Result<hook::detail::ReservedTarget>
1220 16990 reserve_target(const hook::Target &target, const hook::Options &options, const char *where) noexcept
1221 {
1222 16990 Result<std::uintptr_t> resolved = resolve_target(target);
1223
2/2
✓ Branch 4 → 5 taken 3 times.
✓ Branch 4 → 9 taken 16986 times.
16988 if (!resolved)
1224 {
1225 3 return std::unexpected(resolved.error());
1226 }
1227 16986 const std::uintptr_t address = *resolved;
1228
2/2
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 14 taken 16984 times.
16986 if (address == 0)
1229 {
1230 2 return std::unexpected(Error{ErrorCode::InvalidTargetAddress, where});
1231 }
1232
1233 // try_reserve_hook folds the same-kit duplicate check and the id record into one locked step, so a
1234 // concurrent same-target install cannot slip between them.
1235 const detail::HookLedger::Reservation reservation =
1236 16984 detail::HookLedger::instance().try_reserve_hook(address, options.fail_if_already_hooked);
1237
2/2
✓ Branch 16 → 17 taken 21 times.
✓ Branch 16 → 20 taken 16965 times.
16986 if (reservation.status == detail::HookLedger::ReserveStatus::OutOfMemory)
1238 {
1239 // The ledger allocation failed. Fail closed instead of an install of a live but unledgered hook.
1240 21 return std::unexpected(Error{ErrorCode::OutOfMemory, where, address});
1241 }
1242
2/2
✓ Branch 20 → 21 taken 8 times.
✓ Branch 20 → 24 taken 16957 times.
16965 if (reservation.status == detail::HookLedger::ReserveStatus::AlreadyHooked)
1243 {
1244 8 return std::unexpected(Error{ErrorCode::TargetAlreadyHookedByThisKit, where, address});
1245 }
1246 16957 return hook::detail::ReservedTarget{address, reservation.id, reservation.preexisting};
1247 }
1248
1249 /// What a classification under the coordinator found, apart from a refusal.
1250 enum class TargetClassification : std::uint8_t
1251 {
1252 Hookable,
1253 /// A patch window outside the coordinator holds the target. Release the hold, yield, and classify again.
1254 PatchInFlight
1255 };
1256
1257 /**
1258 * @brief Collects the log lines of one classification, so the install emits them after the hold releases.
1259 * @details Holds plain fields only, so a classification under the coordinator allocates nothing.
1260 */
1261 struct ClassificationLog
1262 {
1263 detail::CoordinatorHoldRefusal refused_hold{detail::CoordinatorHoldRefusal::None};
1264 std::optional<detail::TargetWindowVerdict> refused_window;
1265 bool layers_on_this_kit{false};
1266 std::optional<std::uintptr_t> foreign_jump_destination;
1267 bool breakpoint_relocated{false};
1268
1269 17199 void emit(std::string_view where, std::string_view name, std::uintptr_t address) const noexcept
1270 {
1271
2/2
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 7 taken 17196 times.
17199 if (refused_hold != detail::CoordinatorHoldRefusal::None)
1272 {
1273 6 (void)log().try_log(
1274 LogLevel::Warning,
1275 "{}: '{}' cannot hold the process coordinator: {}.",
1276 where,
1277 name,
1278 6 detail::coordinator_hold_refusal_description(refused_hold)
1279 );
1280 }
1281
2/2
✓ Branch 8 → 9 taken 22 times.
✓ Branch 8 → 14 taken 17177 times.
17199 if (refused_window)
1282 {
1283 22 (void)log().try_log(
1284 LogLevel::Warning,
1285 "hook: '{}' refused target 0x{:0{}X}: {}.",
1286 name,
1287 address,
1288 22 sizeof(std::uintptr_t) * 2,
1289 44 detail::target_window_description(*refused_window)
1290 );
1291 }
1292
2/2
✓ Branch 14 → 15 taken 4270 times.
✓ Branch 14 → 18 taken 12929 times.
17199 if (layers_on_this_kit)
1293 {
1294 4270 (void)log().try_log(
1295 LogLevel::Warning,
1296 "hook: '{}' layers on a hook this kit already placed at 0x{:0{}X}. The layers retire "
1297 "in any order.",
1298 name,
1299 address,
1300 4270 sizeof(std::uintptr_t) * 2
1301 );
1302 }
1303
2/2
✓ Branch 19 → 20 taken 3281 times.
✓ Branch 19 → 24 taken 13918 times.
17199 if (foreign_jump_destination)
1304 {
1305 3281 (void)log().try_log(
1306 LogLevel::Warning,
1307 "hook: '{}' detects another module's inline hook at target 0x{:0{}X} "
1308 "(JMP -> 0x{:0{}X}). The new hook layers on top.",
1309 name,
1310 address,
1311 3281 sizeof(std::uintptr_t) * 2,
1312 *foreign_jump_destination,
1313 6562 sizeof(std::uintptr_t) * 2
1314 );
1315 }
1316
2/2
✓ Branch 24 → 25 taken 7 times.
✓ Branch 24 → 29 taken 17192 times.
17199 if (breakpoint_relocated)
1317 {
1318 7 (void)log().try_log(
1319 LogLevel::Warning,
1320 "hook: '{}' target 0x{:0{}X} begins with {}. Installation continues under the "
1321 "Relocate prologue policy.",
1322 name,
1323 address,
1324 7 sizeof(std::uintptr_t) * 2,
1325 14 prologue_risk_description(PrologueRisk::Breakpoint)
1326 );
1327 }
1328 17199 }
1329 };
1330
1331 /**
1332 * @brief Runs the steal-window, foreign-jump, and prologue checks on @p reserved under @p hold (`[B-109]`).
1333 * @return The classification, or the Error that fails the install. Every Error releases the reservation. A
1334 * refused @p hold returns BackendFailed before any target read.
1335 * @details Collects each log line in @p lines. The foreign-jump check runs only for a target that this kit
1336 * does not hook yet.
1337 */
1338 17237 [[nodiscard]] Result<TargetClassification> classify_target_under_coordinator(
1339 const hook::detail::ReservedTarget &reserved,
1340 const hook::Options &options,
1341 const char *where,
1342 const detail::BackendCoordinatorHold &hold,
1343 ClassificationLog &lines
1344 ) noexcept
1345 {
1346 17237 const std::uintptr_t address = reserved.address;
1347 32 const auto refuse = [&reserved](const Error &error) noexcept -> Result<TargetClassification>
1348 {
1349 32 (void)detail::HookLedger::instance().release_hook(reserved.address, reserved.ledger_id);
1350 32 return std::unexpected(error);
1351 17237 };
1352
2/2
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 7 taken 17234 times.
17237 if (!hold)
1353 {
1354 3 lines.refused_hold = hold.refusal();
1355 3 return refuse(Error{ErrorCode::BackendFailed, where, address});
1356 }
1357
1358 // Options::prologue does not alter the window check. Prologue::Relocate must not authorize an unreadable
1359 // prologue.
1360 17234 const detail::TargetWindowResult window = detail::validate_backend_steal_window(address);
1361
2/2
✓ Branch 8 → 9 taken 297 times.
✓ Branch 8 → 11 taken 16937 times.
17234 if (window.verdict == detail::TargetWindowVerdict::PatchInFlight)
1362 {
1363 297 return TargetClassification::PatchInFlight;
1364 }
1365
2/2
✓ Branch 11 → 12 taken 22 times.
✓ Branch 11 → 19 taken 16915 times.
16937 if (window.verdict != detail::TargetWindowVerdict::Ok)
1366 {
1367 22 lines.refused_window = window.verdict;
1368 22 return refuse(
1369 22 Error{
1370
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 22 times.
22 window.verdict == detail::TargetWindowVerdict::Unreadable ? ErrorCode::ReadFaulted
1371 : ErrorCode::TargetPrologueUnsafe,
1372 where,
1373 22 window.detail
1374 }
1375 22 );
1376 }
1377
1378
2/2
✓ Branch 19 → 20 taken 4276 times.
✓ Branch 19 → 21 taken 12639 times.
16915 if (reserved.preexisting)
1379 {
1380 4276 lines.layers_on_this_kit = true;
1381 }
1382 12639 else if (const PrehookDetection prehook = detect_existing_inline_hook(address);
1383
2/2
✓ Branch 22 → 23 taken 3293 times.
✓ Branch 22 → 28 taken 9346 times.
12639 prehook.state == PrehookState::HookedByOtherModule)
1384 {
1385
2/2
✓ Branch 23 → 24 taken 4 times.
✓ Branch 23 → 26 taken 3289 times.
3293 if (options.fail_if_already_hooked)
1386 {
1387 4 return refuse(Error{ErrorCode::TargetAlreadyHookedByAnotherModule, where, address});
1388 }
1389 3289 lines.foreign_jump_destination = prehook.jmp_destination;
1390 }
1391
1392 // An unhooked target can still start with a call thunk or a patched int3.
1393 16911 const PrologueRisk risk = classify_prologue_risk(address);
1394
1/2
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 33 taken 16911 times.
16911 if (risk == PrologueRisk::Unreadable)
1395 {
1396 ✗ return refuse(Error{ErrorCode::ReadFaulted, where, address});
1397 }
1398
2/2
✓ Branch 33 → 34 taken 21 times.
✓ Branch 33 → 38 taken 16890 times.
16911 if (risk == PrologueRisk::Breakpoint)
1399 {
1400
2/2
✓ Branch 34 → 35 taken 3 times.
✓ Branch 34 → 37 taken 18 times.
21 if (options.prologue == hook::Prologue::Fail)
1401 {
1402 3 return refuse(Error{ErrorCode::TargetPrologueUnsafe, where, address});
1403 }
1404 18 lines.breakpoint_relocated = true;
1405 }
1406 16908 return TargetClassification::Hookable;
1407 }
1408
1409 /**
1410 * @brief Classifies @p reserved and runs @p create_backend under one coordinator hold.
1411 * @return The created backend hook, or the Error that fails the install. Every Error releases the reservation.
1412 * @details On success @p hold stays held, and @p lines keeps the lines of the final pass. The caller emits them
1413 * after it releases @p hold. Every other return releases the hold and emits the lines. A patch window
1414 * outside the coordinator releases the hold, yields one scheduler tick, and classifies again, with no
1415 * attempt count and no time cap. The first such pass logs one line. An exception from
1416 * @p create_backend leaves the reservation and the hold to the caller.
1417 */
1418 template <class CreateBackend>
1419 16940 [[nodiscard]] auto create_backend_under_coordinator(
1420 const hook::detail::ReservedTarget &reserved,
1421 const hook::Options &options,
1422 std::string_view name,
1423 const char *where,
1424 std::optional<detail::BackendCoordinatorHold> &hold,
1425 ClassificationLog &lines,
1426 CreateBackend &&create_backend
1427 ) -> Result<typename std::invoke_result_t<CreateBackend &>::value_type>
1428 {
1429 16940 bool patch_wait_logged = false;
1430
5/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 58 → 59 taken 9401 times.
✓ Branch 58 → 60 taken 297 times.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✓ Branch 58 → 59 taken 3267 times.
✗ Branch 58 → 60 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 58 → 59 taken 2233 times.
✗ Branch 58 → 60 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 58 → 59 taken 2001 times.
✗ Branch 58 → 60 not taken.
17237 for (;;)
1431 {
1432 17237 lines = ClassificationLog{};
1433 17237 std::optional<std::invoke_result_t<CreateBackend &>> created;
1434 17237 hold.emplace(detail::WaitUntilHeld{where, name});
1435 const Result<TargetClassification> classified =
1436 17237 classify_target_under_coordinator(reserved, options, where, *hold, lines);
1437
19/24
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 8 → 9 taken 9708 times.
✓ Branch 8 → 12 taken 28 times.
✓ Branch 10 → 11 taken 9411 times.
✓ Branch 10 → 12 taken 297 times.
✓ Branch 13 → 14 taken 9411 times.
✓ Branch 13 → 26 taken 325 times.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✓ Branch 8 → 9 taken 3265 times.
✓ Branch 8 → 12 taken 2 times.
✓ Branch 10 → 11 taken 3265 times.
✗ Branch 10 → 12 not taken.
✓ Branch 13 → 14 taken 3265 times.
✓ Branch 13 → 26 taken 2 times.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 8 → 9 taken 2231 times.
✓ Branch 8 → 12 taken 2 times.
✓ Branch 10 → 11 taken 2231 times.
✗ Branch 10 → 12 not taken.
✓ Branch 13 → 14 taken 2231 times.
✓ Branch 13 → 26 taken 2 times.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 8 → 9 taken 2001 times.
✗ Branch 8 → 12 not taken.
✓ Branch 10 → 11 taken 2001 times.
✗ Branch 10 → 12 not taken.
✓ Branch 13 → 14 taken 2001 times.
✗ Branch 13 → 26 not taken.
17237 if (classified && *classified == TargetClassification::Hookable)
1438 {
1439
5/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 14 → 15 taken 9373 times.
✓ Branch 14 → 62 taken 38 times.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✓ Branch 14 → 15 taken 3265 times.
✗ Branch 14 → 62 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 14 → 15 taken 2231 times.
✗ Branch 14 → 62 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 14 → 15 taken 2001 times.
✗ Branch 14 → 62 not taken.
16908 created.emplace(create_backend());
1440
6/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 19 → 20 taken 9371 times.
✓ Branch 19 → 26 taken 2 times.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✓ Branch 19 → 20 taken 3257 times.
✓ Branch 19 → 26 taken 8 times.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 19 → 20 taken 2231 times.
✗ Branch 19 → 26 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 19 → 20 taken 2001 times.
✗ Branch 19 → 26 not taken.
16870 if (*created)
1441 {
1442
4/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 21 → 22 taken 9371 times.
✗ Branch 21 → 70 not taken.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✓ Branch 21 → 22 taken 3257 times.
✗ Branch 21 → 70 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 21 → 22 taken 2231 times.
✗ Branch 21 → 70 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 21 → 22 taken 2001 times.
✗ Branch 21 → 70 not taken.
33720 return std::move(created->value());
1443 }
1444 }
1445 339 hold.reset();
1446 339 lines.emit(where, name, reserved.address);
1447
5/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 30 → 31 taken 28 times.
✓ Branch 30 → 35 taken 299 times.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✓ Branch 30 → 31 taken 2 times.
✓ Branch 30 → 35 taken 8 times.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✓ Branch 30 → 31 taken 2 times.
✗ Branch 30 → 35 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 35 not taken.
339 if (!classified)
1448 {
1449 32 return std::unexpected(classified.error());
1450 }
1451
3/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 36 → 37 taken 297 times.
✓ Branch 36 → 44 taken 2 times.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 44 taken 8 times.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 44 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 44 not taken.
307 if (*classified == TargetClassification::PatchInFlight)
1452 {
1453
2/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 38 → 39 taken 1 time.
✓ Branch 38 → 42 taken 296 times.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 42 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 42 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 42 not taken.
297 if (!std::exchange(patch_wait_logged, true))
1454 {
1455 1 (void)log().try_log(
1456 LogLevel::Warning,
1457 "{}: '{}' waits for a patch window at 0x{:0{}X} that another patcher holds outside the "
1458 "process coordinator.",
1459 where,
1460 name,
1461 1 reserved.address,
1462 1 sizeof(std::uintptr_t) * 2
1463 );
1464 }
1465
1/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 42 → 43 taken 297 times.
✗ Branch 42 → 70 not taken.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 70 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 70 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 70 not taken.
297 ::Sleep(1);
1466 297 continue;
1467 }
1468
2/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 49 → 50 taken 2 times.
✗ Branch 49 → 63 not taken.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✓ Branch 49 → 50 taken 8 times.
✗ Branch 49 → 63 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 63 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 63 not taken.
20 log().error(
1469 "{}: backend create failed for '{}' at {}: {}",
1470 where,
1471 name,
1472
2/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 48 → 49 taken 2 times.
✗ Branch 48 → 66 not taken.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✓ Branch 48 → 49 taken 8 times.
✗ Branch 48 → 66 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 66 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 66 not taken.
20 format::format_address(reserved.address),
1473
2/8
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_inline(DetourModKit::hook::InlineRequest, DetourModKit::hook::detail::ReservedTarget const&, void*, std::optional<DetourModKit::hook::CountedThunk>)::{lambda()#1}&&):
✓ Branch 47 → 48 taken 2 times.
✗ Branch 47 → 69 not taken.
std::expected<std::invoke_result<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::mid_at(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda()#1}&&):
✓ Branch 47 → 48 taken 8 times.
✗ Branch 47 → 69 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 69 not taken.
std::expected<std::invoke_result<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&>::type::value_type, DetourModKit::Error> DetourModKit::(anonymous namespace)::create_backend_under_coordinator<DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}>(DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, std::basic_string_view<char, std::char_traits<char> >, char const*, std::optional<DetourModKit::detail::BackendCoordinatorHold>&, DetourModKit::(anonymous namespace)::ClassificationLog&, DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&)::{lambda()#1}::operator()() const::{lambda()#1}&&):
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 69 not taken.
20 backend_error_string(created->error())
1474 );
1475 10 (void)detail::HookLedger::instance().release_hook(reserved.address, reserved.ledger_id);
1476 10 return std::unexpected(Error{ErrorCode::BackendFailed, where, reserved.address});
1477 }
1478 }
1479
1480 using detail::apply_backend;
1481 using detail::backend_value_or;
1482 using detail::emit_lifecycle;
1483 using detail::inline_trampoline;
1484 using detail::PatchWitness;
1485 using detail::RemovalPopulationState;
1486 using detail::try_backend_disable;
1487 using detail::witness_description;
1488 using detail::witness_of;
1489 using detail::witness_permits_write;
1490
1491 /**
1492 * @brief Runs the teardown backend disable and reports the later owner of the target bytes.
1493 * @details The witness is taken whatever the disable reported, because the two disagree in both directions.
1494 * The byte class is the complete verdict. Only @ref PatchWitness::Original authorizes backend
1495 * destruction.
1496 * @param refusal Receives the coordinator refusal of a failed disable.
1497 */
1498 template <class BackendVariant>
1499 [[nodiscard]] PatchWitness
1500 10434 run_teardown_restore(BackendVariant &backend, DetourModKit::detail::CoordinatorRefusal &refusal) noexcept
1501 {
1502 // Classify before the restore, so foreign bytes are refused rather than overwritten.
1503 10434 const PatchWitness before = witness_of(backend);
1504
2/2
✓ Branch 4 → 5 taken 65 times.
✓ Branch 4 → 6 taken 10369 times.
10434 if (!witness_permits_write(before))
1505 {
1506 65 return before;
1507 }
1508
1509 #if defined(DMK_ENABLE_TEST_SEAMS)
1510 // A false result or exception models a pre-mutation failure because it suppresses the backend call. The
1511 // witness below reconciles real backend exceptions after try_backend_disable contains them.
1512 10369 bool run_restore = true;
1513 try
1514 {
1515
2/2
✓ Branch 6 → 7 taken 6 times.
✓ Branch 6 → 9 taken 10363 times.
10369 if (auto *override_fn = DetourModKit::detail::g_hook_teardown_restore_override)
1516 {
1517
2/2
✓ Branch 7 → 8 taken 5 times.
✓ Branch 7 → 18 taken 1 time.
6 run_restore = override_fn();
1518 }
1519 }
1520 1 catch (...)
1521 {
1522 1 run_restore = false;
1523 }
1524
2/2
✓ Branch 9 → 10 taken 10363 times.
✓ Branch 9 → 12 taken 6 times.
10369 if (run_restore)
1525 #endif
1526 {
1527 10363 (void)backend_value_or(
1528 backend,
1529 false,
1530 20726 [&refusal](auto &one) noexcept { return try_backend_disable(one, &refusal); }
1531 );
1532 }
1533 10369 const PatchWitness after = witness_of(backend);
1534
2/2
✓ Branch 13 → 14 taken 10359 times.
✓ Branch 13 → 16 taken 10 times.
10369 if (after == PatchWitness::Original)
1535 {
1536 // The byte witness proves the target cannot reach this trampoline. Clear a stale backend flag so its
1537 // destructor cannot retry the caught operation outside this noexcept containment boundary.
1538 20718 (void)apply_backend(backend, [](auto &one) noexcept { one.reconcile_enabled(false); });
1539 }
1540 10369 return after;
1541 }
1542
1543 /**
1544 * @brief Bounds the wait for route entrants, displaced callees, and unresolved continuations.
1545 */
1546 constexpr auto ROUTE_DRAIN_TIMEOUT = std::chrono::seconds{1};
1547
1548 /**
1549 * @brief Waits for the backend route to empty, or reports that proof of an empty route timed out.
1550 * @details The zero read that ends the wait proves the mid stub unreachable (`[B-108]`).
1551 * @note A false return never licenses reclamation. The caller must retain the backend.
1552 */
1553 16006 template <class BackendVariant> [[nodiscard]] bool drain_backend_route(BackendVariant &backend) noexcept
1554 {
1555 16006 return DetourModKit::detail::drain_until_zero(
1556 16006 [&backend]() noexcept
1557 {
1558 17093 return backend_value_or(
1559 backend,
1560 std::size_t{1},
1561 34186 [](auto &one) noexcept { return one.observe_route_entries(); }
1562 17093 );
1563 },
1564 32012 std::chrono::steady_clock::now() + ROUTE_DRAIN_TIMEOUT
1565 16006 );
1566 }
1567
1568 /**
1569 * @brief Switches the relay of a counted hook off and proves its detour idle within the route bound
1570 * (`[B-106]`).
1571 * @return Null when the detour drained, or a phrase that completes the pin warning.
1572 */
1573 template <class BackendVariant>
1574 4249 [[nodiscard]] const char *drain_counted_hook(BackendVariant &backend, const hook::CountedThunk &thunk) noexcept
1575 {
1576 4249 const std::array<safetyhook::AddressRange, 1> ranges{thunk.range};
1577
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 4249 times.
4249 if (hook::detail::current_thread_returns_into(ranges))
1578 {
1579 ✗ return "the teardown runs inside its own counted detour";
1580 }
1581
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 4249 times.
4249 if (!DetourModKit::detail::switch_backend(backend, false))
1582 {
1583 ✗ return "the backend cannot switch its relay off";
1584 }
1585 4249 std::array<const safetyhook::ReturnSites *, hook::COUNTED_HELPER_SITE_LISTS> sites{};
1586
2/2
✓ Branch 13 → 10 taken 7 times.
✓ Branch 13 → 14 taken 4249 times.
4256 for (std::size_t i = 0; i < thunk.helper_site_lists; ++i)
1587 {
1588 7 sites[i] = &thunk.helper_sites[i];
1589 }
1590 4249 const std::array<hook::detail::CountedBlock *, 1> blocks{thunk.block};
1591 8498 const hook::detail::CountedDrain drained = hook::detail::drain_counted(
1592 4249 ranges,
1593 4249 std::span<const safetyhook::ReturnSites *const>{sites.data(), thunk.helper_site_lists},
1594 4249 blocks,
1595 4249 std::chrono::steady_clock::now() + ROUTE_DRAIN_TIMEOUT
1596 );
1597
2/2
✓ Branch 22 → 23 taken 4248 times.
✓ Branch 22 → 24 taken 1 time.
4249 return drained.idle ? nullptr : "a counted call stayed inside its detour past the drain bound";
1598 }
1599
1600 /**
1601 * @brief Pins a backend whose detour can stay reachable: it leaks the Impl and keeps its module reference.
1602 * @details A caller that holds the target install-serialization slot passes @p ledger, and the helper
1603 * releases the slot. The creation-order entry stays, so is_target_hooked still reports the hooked
1604 * target. Hook::Impl is private to Hook, so each ~Hook phase helper deduces the Impl type as a
1605 * template parameter.
1606 * @param reason A string literal that completes the warning sentence.
1607 */
1608 template <class HookImpl>
1609 6 hook::TeardownOutcome pin_backend_with_live_detour(
1610 std::unique_ptr<HookImpl> &impl,
1611 detail::HookLedger *ledger,
1612 const std::string &name,
1613 std::uintptr_t target,
1614 std::uint64_t ledger_id,
1615 diagnostics::HookKind kind,
1616 const char *reason
1617 ) noexcept
1618 {
1619 6 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
1620 6 (void)impl.release();
1621
2/2
✓ Branch 4 → 5 taken 5 times.
✓ Branch 4 → 6 taken 1 time.
6 if (ledger != nullptr)
1622 {
1623 5 ledger->release_target_slot(target, ledger_id);
1624 }
1625 6 (void)log().try_log(
1626 LogLevel::Warning,
1627 "hook: '{}' at 0x{:0{}X} leaked its backend during teardown, so its detour stays reachable: {}.",
1628 name,
1629 target,
1630 6 sizeof(std::uintptr_t) * 2,
1631 reason
1632 );
1633 6 emit_lifecycle(
1634 name,
1635 ledger_id,
1636 kind,
1637 diagnostics::HookTransition::Removed,
1638 RemovalPopulationState{
1639 .remains_live = true,
1640 }
1641 );
1642 6 return hook::TeardownOutcome::Pinned;
1643 }
1644
1645 /// Names why a layer retires by bypass in place of a restore.
1646 struct RetirementCause
1647 {
1648 /// The newer hooks of this kit, or zero when @ref detail proves the newer layer.
1649 std::size_t newer_layers{0};
1650 /// The byte witness or coordinator text, or empty for a claimed position.
1651 std::string_view detail{};
1652 };
1653
1654 /// The outcome of the teardown restore.
1655 enum class TeardownRestore : std::uint8_t
1656 {
1657 Restored,
1658 Pinned,
1659 /// A newer layer, foreign bytes, or unreadable bytes refused the restore. The hook retires by bypass.
1660 Retire,
1661 };
1662
1663 /**
1664 * @brief Restores the target prologue under the process coordinator, or decides how the hook retires.
1665 * @details The caller holds the target install-serialization slot. The helper releases it after a pin. A
1666 * Retire outcome fills @p cause and, before it releases the coordinator, leaves a bypassed mid route
1667 * closed and reopens any other.
1668 */
1669 template <class HookImpl>
1670 10434 [[nodiscard]] TeardownRestore restore_target_or_pin_backend(
1671 std::unique_ptr<HookImpl> &impl,
1672 detail::HookLedger &ledger,
1673 const std::string &name,
1674 std::uintptr_t target,
1675 std::uint64_t ledger_id,
1676 diagnostics::HookKind kind,
1677 RetirementCause &cause
1678 ) noexcept
1679 {
1680 // Close the backend-owned route before restore, so admitted callers stay counted across the generated
1681 // stub. For an Unwaitable self-owned mid teardown, drain_route_or_retain_backend skips the drain and
1682 // retains the route. The helper takes the process coordinator before it closes the route, because the
1683 // coordinator wait export can be this closed route. A refused coordinator leaves the route open. The
1684 // backend disable then acquires the coordinator itself and closes the route, or it refuses the restore.
1685 10434 std::optional<safetyhook::ProcessCoordinator> coordinator{std::in_place};
1686
2/2
✓ Branch 5 → 6 taken 10426 times.
✓ Branch 5 → 9 taken 8 times.
10434 if (*coordinator)
1687 {
1688 20852 (void)apply_backend(impl->backend, [](auto &backend) noexcept { backend.begin_route_rundown(); });
1689 }
1690 // Disable the backend here instead of in ~Impl. Its backend destructor discards a failed disable and
1691 // reclaims storage regardless. Only a prologue at its original bytes authorizes backend destruction.
1692 // Foreign and Indeterminate bytes write nothing (see run_teardown_restore) and retire the hook.
1693 10434 DetourModKit::detail::CoordinatorRefusal refusal = DetourModKit::detail::CoordinatorRefusal::None;
1694 10434 const PatchWitness restore = run_teardown_restore(impl->backend, refusal);
1695 // Bytes that are not this hook's own, or a coordinator that saw a newer participant, mean that a restore
1696 // can clobber another layer. Only an own patch after a failed or thrown restore keeps the pin.
1697 10434 const bool newer_participant = refusal == DetourModKit::detail::CoordinatorRefusal::LayerConflict;
1698
6/6
✓ Branch 11 → 12 taken 10372 times.
✓ Branch 11 → 15 taken 62 times.
✓ Branch 12 → 13 taken 10369 times.
✓ Branch 12 → 15 taken 3 times.
✓ Branch 13 → 14 taken 10 times.
✓ Branch 13 → 23 taken 10359 times.
10434 if (restore == PatchWitness::Foreign || restore == PatchWitness::Indeterminate ||
1699
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 23 taken 10 times.
10 (restore == PatchWitness::OwnedPatch && newer_participant))
1700 {
1701 // Retirement takes the coordinator again, and its wait export can be this route. A bypassed route
1702 // stays closed, so no caller enters the tombstoned adapter before the drain.
1703 65 const bool bypassed = impl->bypassed;
1704 65 (void)apply_backend(
1705 65 impl->backend,
1706 195 [bypassed](auto &backend) noexcept
1707
2/2
✓ Branch 2 → 3 taken 15 times.
✓ Branch 2 → 4 taken 50 times.
65 { bypassed ? backend.finish_route_rundown() : backend.cancel_route_rundown(); }
1708 );
1709 65 coordinator.reset();
1710 65 cause.detail = restore == PatchWitness::OwnedPatch
1711
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 65 times.
65 ? DetourModKit::detail::coordinator_refusal_description(refusal)
1712 65 : witness_description(restore);
1713 65 return TeardownRestore::Retire;
1714 }
1715
2/2
✓ Branch 23 → 24 taken 10 times.
✓ Branch 23 → 42 taken 10359 times.
10369 if (restore != PatchWitness::Original)
1716 {
1717 // A pin keeps the route state from before teardown, so a bypassed route stays closed.
1718 10 const bool bypassed = impl->bypassed;
1719 10 (void)apply_backend(
1720 10 impl->backend,
1721 30 [bypassed](auto &backend) noexcept
1722
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 10 times.
10 { bypassed ? backend.finish_route_rundown() : backend.cancel_route_rundown(); }
1723 );
1724 10 coordinator.reset();
1725 // The target can still dispatch through this trampoline. Pin the Impl to keep its pages mapped. Book
1726 // the leak and keep the creation-order entry, so is_target_hooked stays true.
1727 10 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
1728 10 (void)impl.release();
1729 10 ledger.release_target_slot(target, ledger_id);
1730 10 const std::string_view refusal_text = DetourModKit::detail::coordinator_refusal_description(refusal);
1731 10 (void)log().try_log(
1732 LogLevel::Warning,
1733 "hook: '{}' at 0x{:0{}X} did not restore its target's prologue during teardown ({}{}{}). "
1734 "Teardown leaked the backend, so the possibly reachable trampoline stays mapped. The target "
1735 "remains tracked as hooked.",
1736 name,
1737 target,
1738 10 sizeof(std::uintptr_t) * 2,
1739 20 witness_description(restore),
1740
2/2
✓ Branch 34 → 35 taken 8 times.
✓ Branch 34 → 36 taken 2 times.
10 refusal_text.empty() ? "" : ", ",
1741 refusal_text
1742 );
1743 10 emit_lifecycle(
1744 name,
1745 ledger_id,
1746 kind,
1747 diagnostics::HookTransition::Removed,
1748 RemovalPopulationState{
1749 .remains_live = true,
1750 }
1751 );
1752 10 return TeardownRestore::Pinned;
1753 }
1754 20718 (void)apply_backend(impl->backend, [](auto &backend) noexcept { backend.finish_route_rundown(); });
1755 10359 coordinator.reset();
1756 10359 return TeardownRestore::Restored;
1757 10434 }
1758
1759 /**
1760 * @brief Retires a hook that cannot restore. It switches the hook off, drains a mid route, and vacates the
1761 * position for a later generation of the same hook name.
1762 * @details The caller holds the target install-serialization slot. The helper releases it and keeps the
1763 * creation-order entry, because the position stays in the target's chain. A drained position reaches
1764 * no image code, so the module reference goes. The residue books HookResidue under the
1765 * diagnostics::LeakSubsystem contract. Over the residue budget, a fresh layer keeps the pin.
1766 */
1767 template <class HookImpl>
1768 791 hook::TeardownOutcome retire_by_vacate(
1769 std::unique_ptr<HookImpl> &impl,
1770 detail::HookLedger &ledger,
1771 const std::string &name,
1772 std::uintptr_t target,
1773 std::uint64_t ledger_id,
1774 diagnostics::HookKind kind,
1775 bool was_active,
1776 DetourModKit::detail::MidRundown mid_rundown,
1777 bool has_mid_slot,
1778 std::size_t mid_slot,
1779 RetirementCause cause
1780 ) noexcept
1781 {
1782 791 const bool claimed = DetourModKit::detail::backend_claimed(impl->backend);
1783
6/6
✓ Branch 4 → 5 taken 87 times.
✓ Branch 4 → 9 taken 704 times.
✓ Branch 7 → 8 taken 4 times.
✓ Branch 7 → 9 taken 83 times.
✓ Branch 10 → 11 taken 4 times.
✓ Branch 10 → 15 taken 787 times.
791 if (!claimed && !DetourModKit::detail::residue_fits_budget(impl->backend))
1784 {
1785 // Same route-state rule as the pin in restore_target_or_pin_backend.
1786 4 (void)apply_backend(
1787 4 impl->backend,
1788 12 [was_active](auto &backend) noexcept
1789
2/2
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 4 taken 1 time.
4 { was_active ? backend.cancel_route_rundown() : backend.finish_route_rundown(); }
1790 );
1791 4 return pin_backend_with_live_detour(
1792 impl,
1793 &ledger,
1794 name,
1795 target,
1796 ledger_id,
1797 kind,
1798 "the target or the process route registry reached the residue budget"
1799 4 );
1800 }
1801
1802 // A mid route drains while CLOSING, because a CLOSED route admits bypass traffic that holds entries. The
1803 // coordinator and the stack query come first, because either can call an export that this route hooks.
1804 787 bool drained = true;
1805
2/2
✓ Branch 15 → 16 taken 74 times.
✓ Branch 15 → 32 taken 713 times.
787 if (has_mid_slot)
1806 {
1807 74 const bool caller_owns_route = backend_value_or(
1808 74 impl->backend,
1809 true,
1810 148 [](const auto &backend) noexcept { return backend.caller_owns_route(); }
1811 );
1812 74 const safetyhook::ProcessCoordinator coordinator;
1813 148 (void)apply_backend(impl->backend, [](auto &backend) noexcept { backend.begin_route_rundown(); });
1814
3/6
✓ Branch 21 → 22 taken 74 times.
✗ Branch 21 → 27 not taken.
✓ Branch 22 → 23 taken 74 times.
✗ Branch 22 → 27 not taken.
✓ Branch 25 → 26 taken 74 times.
✗ Branch 25 → 27 not taken.
148 drained = mid_rundown == DetourModKit::detail::MidRundown::Drained && !caller_owns_route &&
1815 74 DetourModKit::detail::drain_closing_route(
1816 74 impl->backend,
1817 DetourModKit::detail::CLOSING_DRAIN_TICK_BUDGET
1818 );
1819 148 (void)apply_backend(impl->backend, [](auto &backend) noexcept { backend.finish_route_rundown(); });
1820 74 }
1821 787 drained =
1822
1/2
✓ Branch 32 → 33 taken 787 times.
✗ Branch 32 → 38 not taken.
1574 drained &&
1823
3/4
✓ Branch 33 → 34 taken 74 times.
✓ Branch 33 → 37 taken 713 times.
✓ Branch 36 → 37 taken 74 times.
✗ Branch 36 → 38 not taken.
861 (!has_mid_slot ||
1824 74 DetourModKit::detail::drain_mid_adapter_entries(DetourModKit::detail::mid_adapter_slots()[mid_slot]));
1825
1/2
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 42 taken 787 times.
787 if (!drained)
1826 {
1827 // A thread can still be inside the detour. The closed route stays closed.
1828 ✗ return pin_backend_with_live_detour(
1829 impl,
1830 &ledger,
1831 name,
1832 target,
1833 ledger_id,
1834 kind,
1835 "a callback or route entrant did not drain before the bypass"
1836 ✗ );
1837 }
1838
1/2
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 47 taken 787 times.
787 if (!DetourModKit::detail::switch_backend(impl->backend, false))
1839 {
1840 ✗ return pin_backend_with_live_detour(
1841 impl,
1842 &ledger,
1843 name,
1844 target,
1845 ledger_id,
1846 kind,
1847 "the backend cannot switch its relay off"
1848 ✗ );
1849 }
1850
1851 787 const HMODULE self_ref = static_cast<HMODULE>(impl->self_ref);
1852 787 const bool vacated = DetourModKit::detail::vacate_backend(impl->backend);
1853
2/2
✓ Branch 50 → 51 taken 786 times.
✓ Branch 50 → 54 taken 1 time.
787 if (vacated)
1854 {
1855 786 impl.reset();
1856
2/2
✓ Branch 52 → 53 taken 74 times.
✓ Branch 52 → 55 taken 712 times.
786 if (has_mid_slot)
1857 {
1858 74 DetourModKit::detail::release_mid_adapter_slot(mid_slot);
1859 }
1860 }
1861 else
1862 {
1863 // The cell stays Owned, so no successor takes this position. The bypassed backend reaches no image
1864 // code, so only the Impl leaks.
1865 1 (void)impl.release();
1866 }
1867
3/4
✓ Branch 55 → 56 taken 704 times.
✓ Branch 55 → 57 taken 83 times.
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 704 times.
787 if (!claimed || !vacated)
1868 {
1869 83 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookResidue);
1870 }
1871 787 ledger.release_target_slot(target, ledger_id);
1872
2/2
✓ Branch 59 → 60 taken 704 times.
✓ Branch 59 → 66 taken 83 times.
787 if (claimed)
1873 {
1874 704 (void)log().try_log(
1875 LogLevel::Info,
1876 "hook: '{}' at 0x{:0{}X} retired its claimed position{}.",
1877 name,
1878 target,
1879 1408 sizeof(std::uintptr_t) * 2,
1880
1/2
✓ Branch 61 → 62 taken 704 times.
✗ Branch 61 → 63 not taken.
704 vacated ? "" : ", which stays owned because the vacate was refused"
1881 );
1882 }
1883
2/2
✓ Branch 66 → 67 taken 21 times.
✓ Branch 66 → 73 taken 62 times.
83 else if (cause.newer_layers != 0)
1884 {
1885 21 (void)log().try_log(
1886 LogLevel::Info,
1887 "hook: '{}' at 0x{:0{}X} retired by bypass under {} newer layer(s). Its position {}.",
1888 name,
1889 target,
1890 42 sizeof(std::uintptr_t) * 2,
1891 cause.newer_layers,
1892
1/2
✓ Branch 68 → 69 taken 21 times.
✗ Branch 68 → 70 not taken.
21 vacated ? "stays for a later generation" : "stays owned because the vacate was refused"
1893 );
1894 }
1895 else
1896 {
1897 62 (void)log().try_log(
1898 LogLevel::Info,
1899 "hook: '{}' at 0x{:0{}X} retired by bypass under a newer layer: {}. Its position {}.",
1900 name,
1901 target,
1902 124 sizeof(std::uintptr_t) * 2,
1903 cause.detail,
1904
2/2
✓ Branch 74 → 75 taken 61 times.
✓ Branch 74 → 76 taken 1 time.
62 vacated ? "stays for a later generation" : "stays owned because the vacate was refused"
1905 );
1906 }
1907 787 DetourModKit::detail::release_module_ref(self_ref, diagnostics::ModulePinReason::Hook);
1908 787 emit_lifecycle(
1909 name,
1910 ledger_id,
1911 kind,
1912 diagnostics::HookTransition::Removed,
1913 RemovalPopulationState{
1914 .was_active = was_active,
1915 }
1916 );
1917 787 return hook::TeardownOutcome::Vacated;
1918 }
1919
1920 /**
1921 * @brief Drains the restored route, or retains it and pins the backend while a caller can still return
1922 * through it.
1923 * @details The caller holds the target install-serialization slot. The helper releases it on a false return.
1924 * @return True when the route drained, or false when the helper pinned the backend.
1925 */
1926 template <class HookImpl>
1927 16013 [[nodiscard]] bool drain_route_or_retain_backend(
1928 std::unique_ptr<HookImpl> &impl,
1929 detail::HookLedger &ledger,
1930 const std::string &name,
1931 std::uintptr_t target,
1932 std::uint64_t ledger_id,
1933 diagnostics::HookKind kind,
1934 bool was_active,
1935 DetourModKit::detail::MidRundown mid_rundown
1936 ) noexcept
1937 {
1938 // A callback frame resolves through mid_rundown. Otherwise only a displaced call can return into this
1939 // route from the caller stack. A hook from inline_at publishes no gateway, and a mid gateway reaches its
1940 // stub without a wrapper call.
1941 16013 const bool caller_owns_route = backend_value_or(
1942 16013 impl->backend,
1943 true,
1944 32026 [](const auto &backend) noexcept { return backend.caller_owns_route(); }
1945 );
1946
2/2
✓ Branch 4 → 5 taken 16008 times.
✓ Branch 4 → 9 taken 5 times.
32021 const bool route_drained = mid_rundown != DetourModKit::detail::MidRundown::Drained ||
1947
4/4
✓ Branch 5 → 6 taken 16006 times.
✓ Branch 5 → 10 taken 2 times.
✓ Branch 8 → 9 taken 16000 times.
✓ Branch 8 → 10 taken 6 times.
16008 (!caller_owns_route && drain_backend_route(impl->backend));
1948
1949
4/4
✓ Branch 11 → 12 taken 16008 times.
✓ Branch 11 → 13 taken 5 times.
✓ Branch 12 → 13 taken 8 times.
✓ Branch 12 → 30 taken 16000 times.
16013 if (mid_rundown != DetourModKit::detail::MidRundown::Drained || !route_drained)
1950 {
1951 // A nonlocal exit can abandon its entry. Retention keeps the same lifetime as an unresolved entrant.
1952 13 const char *blocked_stage =
1953 mid_rundown == DetourModKit::detail::MidRundown::Unwaitable
1954
2/2
✓ Branch 13 → 14 taken 9 times.
✓ Branch 13 → 19 taken 4 times.
22 ? "teardown cannot wait on the caller's callback"
1955
2/2
✓ Branch 14 → 15 taken 8 times.
✓ Branch 14 → 18 taken 1 time.
9 : mid_rundown == DetourModKit::detail::MidRundown::Expired ? "the callback drain expired"
1956
2/2
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 17 taken 6 times.
8 : caller_owns_route ? "an unresolved continuation or nonlocal exit "
1957 "has a possible return on the caller stack"
1958 : "an unresolved continuation or nonlocal exit did not drain";
1959 // A live record refuses every older layer on this target.
1960 26 (void)apply_backend(impl->backend, [](auto &backend) noexcept { backend.retain_route(); });
1961 13 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
1962 13 (void)impl.release();
1963 13 (void)ledger.release_hook(target, ledger_id);
1964 13 (void)log().try_log(
1965 LogLevel::Warning,
1966 "hook: '{}' at 0x{:0{}X} retained its backend because {}. "
1967 "The target is restored. The backend and module references remain pinned.",
1968 name,
1969 target,
1970 13 sizeof(std::uintptr_t) * 2,
1971 blocked_stage
1972 );
1973 13 emit_lifecycle(
1974 name,
1975 ledger_id,
1976 kind,
1977 diagnostics::HookTransition::Removed,
1978 RemovalPopulationState{
1979 .was_active = was_active,
1980 }
1981 );
1982 13 return false;
1983 }
1984 16000 return true;
1985 }
1986
1987 /**
1988 * @brief Retains the route and pins the backend when the bounded drain expires with a thread inside the
1989 * adapter body.
1990 * @details The caller holds the target install-serialization slot. The helper releases it.
1991 */
1992 template <class HookImpl>
1993 2 void retain_backend_for_busy_adapter(
1994 std::unique_ptr<HookImpl> &impl,
1995 detail::HookLedger &ledger,
1996 const std::string &name,
1997 std::uintptr_t target,
1998 std::uint64_t ledger_id,
1999 diagnostics::HookKind kind,
2000 bool was_active
2001 ) noexcept
2002 {
2003 // The adapter_entries counter is the slot-reuse authority, so the slot and stub stay retained. The target
2004 // holds its original bytes, so release_hook drops the ledger entry.
2005 4 (void)apply_backend(impl->backend, [](auto &backend) noexcept { backend.retain_route(); });
2006 2 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
2007 2 (void)impl.release();
2008 2 (void)ledger.release_hook(target, ledger_id);
2009 2 (void)log().try_log(
2010 LogLevel::Warning,
2011 "hook: mid hook '{}' at 0x{:0{}X} was torn down while a thread can still be inside its adapter "
2012 "body past its bounded drain. The target was restored, but the backend and adapter slot are "
2013 "pinned so that thread can return through its stub.",
2014 name,
2015 target,
2016 2 sizeof(std::uintptr_t) * 2
2017 );
2018 2 emit_lifecycle(
2019 name,
2020 ledger_id,
2021 kind,
2022 diagnostics::HookTransition::Removed,
2023 RemovalPopulationState{
2024 .was_active = was_active,
2025 }
2026 );
2027 2 }
2028
2029 /**
2030 * @brief Finishes a restored backend that release_backend tore down, then releases its adapter slot, ledger
2031 * entry, and module reference.
2032 * @details A caller that holds the target install-serialization slot passes @p ledger, and the helper releases
2033 * it. A retained route keeps the Impl, the adapter slot, and the module reference pinned, except a
2034 * residue that reaches no image code (`[B-108]`).
2035 */
2036 template <class HookImpl>
2037 15998 hook::TeardownOutcome reclaim_restored_backend(
2038 std::unique_ptr<HookImpl> &impl,
2039 detail::HookLedger *ledger,
2040 const std::string &name,
2041 std::uintptr_t target,
2042 std::uint64_t ledger_id,
2043 bool has_mid_slot,
2044 std::size_t mid_slot
2045 ) noexcept
2046 {
2047 // release_module_ref calls FreeLibrary, which takes the loader lock. release_hook releases the target
2048 // install-serialization slot before that call, which prevents a lock-order inversion against a DllMain
2049 // install parked on this slot. The caller still executes this module's code and the host holds its own
2050 // load reference, so this release is never the terminal one.
2051 15998 const HMODULE self_ref = static_cast<HMODULE>(impl->self_ref);
2052 // The route verdict must outlive the Impl, so the helper reads it first.
2053 15998 const bool route_retained = backend_value_or(
2054 15998 impl->backend,
2055 false,
2056 31996 [](const auto &backend) noexcept { return backend.route_retained(); }
2057 );
2058 31996 const char *const retention_reason = backend_value_or(
2059 15998 impl->backend,
2060 "route idle proof refused",
2061 31996 [](const auto &backend) noexcept { return backend.route_retention_reason(); }
2062 );
2063 const DetourModKit::detail::IdleRefusalSentence refusal =
2064 15998 DetourModKit::detail::describe_idle_refusal(backend_value_or(
2065 15998 impl->backend,
2066 safetyhook::IdleRefusal{},
2067 31996 [](const auto &backend) noexcept { return backend.idle_refusal(); }
2068 ));
2069 // A raw hook that failed the idle proof keeps only its trampoline in allocator memory. A mid hook with a
2070 // freed stub keeps only its gateway and trampoline (`[B-108]`). The restored target and the switched-off
2071 // relay or route reach no image code, so the residue releases every reference.
2072 15998 const auto *const inline_backend = std::get_if<safetyhook::InlineHook>(&impl->backend);
2073 15998 const auto *const mid_backend = std::get_if<safetyhook::MidHook>(&impl->backend);
2074 15998 const bool trampoline_residue =
2075
6/6
✓ Branch 14 → 15 taken 25 times.
✓ Branch 14 → 19 taken 15973 times.
✓ Branch 15 → 16 taken 4 times.
✓ Branch 15 → 19 taken 21 times.
✓ Branch 17 → 18 taken 3 times.
✓ Branch 17 → 19 taken 1 time.
16002 route_retained && inline_backend != nullptr &&
2076 4 inline_backend->route_retention_cause() == safetyhook::RouteRetentionReason::IdleProofFailed;
2077 15998 const bool route_residue =
2078
7/8
✓ Branch 20 → 21 taken 25 times.
✓ Branch 20 → 29 taken 15973 times.
✓ Branch 21 → 22 taken 21 times.
✓ Branch 21 → 29 taken 4 times.
✓ Branch 23 → 24 taken 21 times.
✗ Branch 23 → 29 not taken.
✓ Branch 25 → 26 taken 9 times.
✓ Branch 25 → 28 taken 12 times.
16028 route_retained && mid_backend != nullptr && mid_backend->stub_freed() &&
2079
2/2
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 29 taken 8 times.
30 (mid_backend->route_retention_cause() == safetyhook::RouteRetentionReason::IdleProofFailed ||
2080 9 mid_backend->route_retention_cause() == safetyhook::RouteRetentionReason::EntryHeld);
2081
4/4
✓ Branch 30 → 31 taken 15995 times.
✓ Branch 30 → 32 taken 3 times.
✓ Branch 31 → 32 taken 13 times.
✓ Branch 31 → 33 taken 15982 times.
15998 const bool residue = trampoline_residue || route_residue;
2082
4/4
✓ Branch 34 → 35 taken 25 times.
✓ Branch 34 → 37 taken 15973 times.
✓ Branch 35 → 36 taken 9 times.
✓ Branch 35 → 37 taken 16 times.
15998 const bool pin_references = route_retained && !residue;
2083
2/2
✓ Branch 38 → 39 taken 9 times.
✓ Branch 38 → 41 taken 15989 times.
15998 if (pin_references)
2084 {
2085 // A retained route preserves every provider reference.
2086 9 (void)impl.release();
2087 9 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
2088 }
2089 else
2090 {
2091 15989 impl.reset();
2092 }
2093
2/2
✓ Branch 42 → 43 taken 16 times.
✓ Branch 42 → 44 taken 15982 times.
15998 if (residue)
2094 {
2095 16 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookResidue);
2096 }
2097
4/4
✓ Branch 44 → 45 taken 5157 times.
✓ Branch 44 → 47 taken 10841 times.
✓ Branch 45 → 46 taken 5149 times.
✓ Branch 45 → 47 taken 8 times.
15998 if (has_mid_slot && !pin_references)
2098 {
2099 5149 DetourModKit::detail::release_mid_adapter_slot(mid_slot);
2100 }
2101
2/2
✓ Branch 47 → 48 taken 15875 times.
✓ Branch 47 → 49 taken 123 times.
15998 if (ledger != nullptr)
2102 {
2103 15875 (void)ledger->release_hook(target, ledger_id);
2104 }
2105
2/2
✓ Branch 49 → 50 taken 9 times.
✓ Branch 49 → 54 taken 15989 times.
15998 if (pin_references)
2106 {
2107 9 (void)log().try_log(
2108 LogLevel::Warning,
2109 "hook: '{}' at 0x{:0{}X} retained its executable route at teardown. "
2110 "The module reference remains held. Reason: {}.{}",
2111 name,
2112 target,
2113 9 sizeof(std::uintptr_t) * 2,
2114 retention_reason,
2115 18 refusal.view()
2116 );
2117 }
2118
2/2
✓ Branch 54 → 55 taken 16 times.
✓ Branch 54 → 62 taken 15982 times.
15998 if (residue)
2119 {
2120 16 (void)log().try_log(
2121 LogLevel::Info,
2122 "hook: '{}' at 0x{:0{}X} restored its target and kept its {}: {}.{}",
2123 name,
2124 target,
2125 32 sizeof(std::uintptr_t) * 2,
2126
2/2
✓ Branch 57 → 58 taken 13 times.
✓ Branch 57 → 59 taken 3 times.
16 route_residue ? "route" : "trampoline",
2127 retention_reason,
2128 32 refusal.view()
2129 );
2130 }
2131
2/2
✓ Branch 62 → 63 taken 9 times.
✓ Branch 62 → 64 taken 15989 times.
15998 if (pin_references)
2132 {
2133 9 return hook::TeardownOutcome::Pinned;
2134 }
2135 15989 DetourModKit::detail::release_module_ref(self_ref, diagnostics::ModulePinReason::Hook);
2136 15989 return hook::TeardownOutcome::Restored;
2137 }
2138
2139 #if defined(DMK_ENABLE_TEST_SEAMS)
2140 /** @brief Fires the publication probe after @p step is complete. */
2141 50445 void note_publish_step(DetourModKit::detail::HookPublishStep step)
2142 {
2143
2/2
✓ Branch 2 → 3 taken 47 times.
✓ Branch 2 → 4 taken 50398 times.
50445 if (auto *probe = DetourModKit::detail::g_hook_publish_probe)
2144 {
2145 47 probe(step);
2146 }
2147 50421 }
2148 #endif
2149
2150 /// Runs the inline_at entry checks, then resolves and reserves the target through @ref reserve_target.
2151 [[nodiscard]] Result<hook::detail::ReservedTarget>
2152 11722 preflight_inline_request(const hook::InlineRequest &request, const void *detour) noexcept
2153 {
2154
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 9 taken 11719 times.
11722 if (std::optional<Error> vetoed = hook::refuse_on_loader_lock("hook::inline_at"))
2155 {
2156 2 return std::unexpected(*vetoed);
2157 }
2158 #if defined(DMK_ENABLE_TEST_SEAMS)
2159 11719 hook::note_loader_veto_passed(DetourModKit::detail::HookLoaderEntry::InlineAt);
2160 #endif
2161
2/2
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 15 taken 11716 times.
11720 if (request.name.empty())
2162 {
2163 2 return std::unexpected(Error{ErrorCode::InvalidArg, "hook::inline_at"});
2164 }
2165
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 19 taken 11715 times.
11716 if (detour == nullptr)
2166 {
2167 1 return std::unexpected(Error{ErrorCode::InvalidDetourFunction, "hook::inline_at"});
2168 }
2169 11715 return reserve_target(request.target, request.options, "hook::inline_at");
2170 }
2171
2172 /// Runs the mid_at entry checks, then resolves and reserves the target through @ref reserve_target.
2173 [[nodiscard]] Result<hook::detail::ReservedTarget>
2174 5278 preflight_mid_request(const hook::MidRequest &request, hook::MidHookFn detour) noexcept
2175 {
2176
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 9 taken 5277 times.
5278 if (std::optional<Error> vetoed = hook::refuse_on_loader_lock("hook::mid_at"))
2177 {
2178 1 return std::unexpected(*vetoed);
2179 }
2180 #if defined(DMK_ENABLE_TEST_SEAMS)
2181 5277 hook::note_loader_veto_passed(DetourModKit::detail::HookLoaderEntry::MidAt);
2182 #endif
2183
2/2
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 15 taken 5275 times.
5277 if (request.name.empty())
2184 {
2185 2 return std::unexpected(Error{ErrorCode::InvalidArg, "hook::mid_at"});
2186 }
2187
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 19 taken 5274 times.
5275 if (detour == nullptr)
2188 {
2189 1 return std::unexpected(Error{ErrorCode::InvalidDetourFunction, "hook::mid_at"});
2190 }
2191 5274 return reserve_target(request.target, request.options, "hook::mid_at");
2192 }
2193
2194 /**
2195 * @brief Claims a mid-adapter slot for @p detour, or rolls back the @p ledger_id reservation.
2196 * @details One adapter exists per live mid hook. The caller's MidAdapterSlotGuard releases the slot on every
2197 * later failure. No adapter entry occurs, because StartDisabled leaves the target unpatched until the
2198 * arm. The callback publishes before the adapter address reaches the backend.
2199 */
2200 [[nodiscard]] Result<std::size_t>
2201 5270 claim_mid_adapter_for_install(std::uintptr_t target, std::uint64_t ledger_id, hook::MidHookFn detour) noexcept
2202 {
2203 5270 const DetourModKit::detail::MidSlotClaim claim = DetourModKit::detail::claim_mid_adapter_slot();
2204
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 9 taken 5269 times.
5270 if (claim.status == DetourModKit::detail::MidSlotClaimStatus::EntryIndexUnavailable)
2205 {
2206 1 (void)DetourModKit::detail::HookLedger::instance().release_hook(target, ledger_id);
2207 1 return std::unexpected(Error{ErrorCode::SystemCallFailed, "hook::mid_at", claim.system_error});
2208 }
2209
2/2
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 15 taken 5268 times.
5269 if (claim.status != DetourModKit::detail::MidSlotClaimStatus::Claimed)
2210 {
2211 1 (void)DetourModKit::detail::HookLedger::instance().release_hook(target, ledger_id);
2212 1 return std::unexpected(Error{ErrorCode::MidHookCapacityExhausted, "hook::mid_at", target});
2213 }
2214 5268 DetourModKit::detail::MidAdapterSlot &slot = DetourModKit::detail::mid_adapter_slots()[claim.index];
2215 5268 slot.target.store(target, std::memory_order_relaxed);
2216 5268 slot.detour.store(detour, std::memory_order_relaxed);
2217 5268 slot.contained_exceptions.store(0, std::memory_order_relaxed);
2218 5268 slot.live.store(true, std::memory_order_release);
2219 5268 return claim.index;
2220 }
2221
2222 /**
2223 * @brief Applies the VmtOptions policy of VmtHook::apply_to to the object's current vptr.
2224 * @details The caller holds the VMT object gate and the handle's method mutex. The caller resolves a vptr at
2225 * its own clone base first, so a clone base here belongs to another VmtHook.
2226 * @return The refusal to return, or nullopt when the apply proceeds.
2227 */
2228 16 [[nodiscard]] std::optional<Error> check_vmt_apply_options(
2229 const hook::VmtOptions &options,
2230 std::uintptr_t current_vptr,
2231 std::string_view name,
2232 const void *object
2233 ) noexcept
2234 {
2235
4/4
✓ Branch 2 → 3 taken 15 times.
✓ Branch 2 → 4 taken 1 time.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 25 taken 14 times.
16 if (options.fail_if_already_hooked || options.fail_on_non_function_pointer)
2236 {
2237
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 10 taken 1 time.
2 if (options.fail_if_already_hooked)
2238 {
2239
1/2
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 10 not taken.
1 if (DetourModKit::detail::HookLedger::instance().is_vmt_clone_base(current_vptr))
2240 {
2241 1 return Error{ErrorCode::HookAlreadyExists, "hook::vmt_apply", current_vptr};
2242 }
2243 }
2244
1/2
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 24 not taken.
1 if (options.fail_on_non_function_pointer)
2245 {
2246 const std::optional<std::uintptr_t> slot0 =
2247 1 DetourModKit::detail::guarded_read<std::uintptr_t>(current_vptr);
2248
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 16 taken 1 time.
1 if (!slot0)
2249 {
2250 ✗ return Error{ErrorCode::InvalidObject, "hook::vmt_apply", current_vptr};
2251 }
2252
1/2
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 22 not taken.
1 if (!looks_like_function_vmt_slot(*slot0))
2253 {
2254 1 return Error{ErrorCode::InvalidObject, "hook::vmt_apply", *slot0};
2255 }
2256 }
2257 ✗ }
2258
2/2
✓ Branch 27 → 28 taken 4 times.
✓ Branch 27 → 31 taken 10 times.
14 else if (DetourModKit::detail::HookLedger::instance().is_vmt_clone_base(current_vptr))
2259 {
2260 // The permissive default permits a chain on a clone that another same-kit VmtHook owns. This copies its
2261 // hooked slots into the "original" snapshot of the applying handle, which creates a silent double hook.
2262 // Proceed per contract but warn.
2263 4 (void)log().try_log(
2264 LogLevel::Warning,
2265 "hook::vmt_apply: VMT hook '{}' targets object 0x{:0{}X} with vptr 0x{:0{}X}. Another DMK VMT "
2266 "hook owns that clone. That clone's hooked slots become this hook's "
2267 "original. Set VmtOptions::fail_if_already_hooked to refuse instead.",
2268 name,
2269 8 reinterpret_cast<std::uintptr_t>(object),
2270 8 sizeof(std::uintptr_t) * 2,
2271 current_vptr,
2272 4 sizeof(std::uintptr_t) * 2
2273 );
2274 }
2275 14 return std::nullopt;
2276 }
2277
2278 /**
2279 * @brief Applies the VmtOptions policy of vmt_for to the object's current vptr.
2280 * @details The caller holds the VMT object gate.
2281 * @return The refusal to return, or nullopt when the clone proceeds.
2282 */
2283 127 [[nodiscard]] std::optional<Error> check_vmt_for_options(
2284 const hook::VmtOptions &options,
2285 std::uintptr_t current_vptr,
2286 std::string_view name,
2287 const void *object
2288 ) noexcept
2289 {
2290
4/4
✓ Branch 2 → 3 taken 124 times.
✓ Branch 2 → 4 taken 3 times.
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 28 taken 120 times.
127 if (options.fail_if_already_hooked || options.fail_on_non_function_pointer)
2291 {
2292
6/6
✓ Branch 4 → 5 taken 3 times.
✓ Branch 4 → 9 taken 4 times.
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 1 time.
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 13 taken 5 times.
10 if (options.fail_if_already_hooked &&
2293 3 DetourModKit::detail::HookLedger::instance().is_vmt_clone_base(current_vptr))
2294 {
2295 2 return Error{ErrorCode::HookAlreadyExists, "hook::vmt_for", current_vptr};
2296 }
2297
2/2
✓ Branch 13 → 14 taken 4 times.
✓ Branch 13 → 27 taken 1 time.
5 if (options.fail_on_non_function_pointer)
2298 {
2299 const std::optional<std::uintptr_t> slot0 =
2300 4 DetourModKit::detail::guarded_read<std::uintptr_t>(current_vptr);
2301
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 4 times.
4 if (!slot0)
2302 {
2303 ✗ return Error{ErrorCode::InvalidObject, "hook::vmt_for", current_vptr};
2304 }
2305
2/2
✓ Branch 21 → 22 taken 3 times.
✓ Branch 21 → 25 taken 1 time.
4 if (!looks_like_function_vmt_slot(*slot0))
2306 {
2307 3 return Error{ErrorCode::InvalidObject, "hook::vmt_for", *slot0};
2308 }
2309 }
2310 2 }
2311
2/2
✓ Branch 30 → 31 taken 19 times.
✓ Branch 30 → 34 taken 101 times.
120 else if (DetourModKit::detail::HookLedger::instance().is_vmt_clone_base(current_vptr))
2312 {
2313 // For the permissive default, see the associated warning in check_vmt_apply_options. vmt_for creates
2314 // a fresh clone, so it needs no own-clone-base exclusion here.
2315 19 (void)log().try_log(
2316 LogLevel::Warning,
2317 "hook::vmt_for: VMT hook '{}' targets object 0x{:0{}X} with vptr 0x{:0{}X}. Another DMK VMT hook "
2318 "owns that clone. That clone's hooked slots become this hook's "
2319 "original. Set VmtOptions::fail_if_already_hooked to refuse instead.",
2320 name,
2321 38 reinterpret_cast<std::uintptr_t>(object),
2322 38 sizeof(std::uintptr_t) * 2,
2323 current_vptr,
2324 19 sizeof(std::uintptr_t) * 2
2325 );
2326 }
2327 122 return std::nullopt;
2328 }
2329
2330 /**
2331 * @brief Counts the callable slots that bound the vmt_for snapshot capture.
2332 * @details The caller holds the VMT object gate and the process coordinator (`[B-66]`).
2333 * @return A nonzero slot budget, or InvalidObject.
2334 */
2335 [[nodiscard]] Result<std::size_t>
2336 122 count_vmt_clone_budget(std::uintptr_t current_vptr, const void *object) noexcept
2337 {
2338 122 const std::optional<std::size_t> slot_budget = count_vmt_method_slots(current_vptr);
2339
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 8 taken 121 times.
122 if (!slot_budget)
2340 {
2341 1 return std::unexpected(
2342 1 Error{ErrorCode::InvalidObject, "hook::vmt_for", reinterpret_cast<std::uintptr_t>(object)}
2343 1 );
2344 }
2345 // An engaged zero found no callable slot. The clone is unusable by construction.
2346
2/2
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 13 taken 120 times.
121 if (*slot_budget == 0)
2347 {
2348 1 return std::unexpected(Error{ErrorCode::InvalidObject, "hook::vmt_for", current_vptr});
2349 }
2350 120 return *slot_budget;
2351 }
2352
2353 ✗ void log_vmt_coordinator_refusal(
2354 std::string_view name,
2355 const void *object,
2356 DetourModKit::detail::CoordinatorHoldRefusal refusal
2357 ) noexcept
2358 {
2359 ✗ (void)log().try_log(
2360 LogLevel::Warning,
2361 "hook::vmt_for: refused VMT hook '{}' on object 0x{:0{}X}: {}.",
2362 name,
2363 ✗ reinterpret_cast<std::uintptr_t>(object),
2364 ✗ sizeof(std::uintptr_t) * 2,
2365 ✗ DetourModKit::detail::coordinator_hold_refusal_description(refusal)
2366 );
2367 ✗ }
2368
2369 /**
2370 * @brief Logs the created VMT hook and emits its Created event.
2371 * @details The caller must not hold the VMT object gate.
2372 */
2373 void
2374 106 report_vmt_hook_created(std::string_view created_name, std::uint64_t ledger_id, const void *object) noexcept
2375 {
2376 // This post-commit log is best-effort. Contain a format bad_alloc (see hook_method_raw).
2377 try
2378 {
2379
1/2
✓ Branch 4 → 5 taken 105 times.
✗ Branch 4 → 9 not taken.
211 log().info(
2380 "hook::vmt_for: created VMT hook '{}' on object {}.",
2381 created_name,
2382
2/2
✓ Branch 3 → 4 taken 105 times.
✓ Branch 3 → 12 taken 1 time.
211 format::format_address(reinterpret_cast<std::uintptr_t>(object))
2383 );
2384 }
2385 1 catch (...)
2386 {
2387 1 }
2388 106 emit_lifecycle(created_name, ledger_id, diagnostics::HookKind::Vmt, diagnostics::HookTransition::Created);
2389 106 }
2390 } // namespace
2391
2392 namespace detail
2393 {
2394 2509 BackendCoordinatorHold::BackendCoordinatorHold() noexcept
2395 {
2396 2509 acquire();
2397 2509 }
2398
2399 33527 BackendCoordinatorHold::BackendCoordinatorHold(WaitUntilHeld wait) noexcept
2400 {
2401 33527 bool logged = false;
2402
2/2
✓ Branch 18 → 3 taken 6 times.
✓ Branch 18 → 19 taken 33527 times.
33533 for (acquire(); m_refusal == CoordinatorHoldRefusal::Timeout; acquire())
2403 {
2404 const std::uint32_t owner =
2405 6 std::launder(reinterpret_cast<safetyhook::ProcessCoordinator *>(m_storage))->owner_thread();
2406 6 release();
2407
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 6 times.
6 if (std::exchange(logged, true))
2408 {
2409 5 continue;
2410 }
2411
2/2
✓ Branch 9 → 10 taken 5 times.
✓ Branch 9 → 13 taken 1 time.
6 if (owner != 0)
2412 {
2413 5 (void)log().try_log(
2414 LogLevel::Warning,
2415 "{}: '{}' waits for the process coordinator held by thread {}.",
2416 wait.where,
2417 wait.name,
2418 owner
2419 );
2420 5 continue;
2421 }
2422 1 (void)log().try_log(
2423 LogLevel::Warning,
2424 "{}: '{}' waits for the process coordinator held by an unknown thread.",
2425 wait.where,
2426 wait.name
2427 );
2428 }
2429 33527 }
2430
2431 36042 void BackendCoordinatorHold::acquire() noexcept
2432 {
2433 static_assert(
2434 sizeof(safetyhook::ProcessCoordinator) <= STORAGE_BYTES &&
2435 alignof(safetyhook::ProcessCoordinator) <= alignof(void *),
2436 "BackendCoordinatorHold storage must fit the backend coordinator"
2437 );
2438
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 36042 times.
36042 auto *const coordinator = ::new (static_cast<void *>(m_storage)) safetyhook::ProcessCoordinator();
2439 36042 m_constructed = true;
2440 36042 m_held = static_cast<bool>(*coordinator);
2441
4/6
✓ Branch 8 → 9 taken 36025 times.
✓ Branch 8 → 10 taken 8 times.
✗ Branch 8 → 11 not taken.
✓ Branch 8 → 12 taken 7 times.
✓ Branch 8 → 13 taken 2 times.
✗ Branch 8 → 14 not taken.
36042 switch (coordinator->refusal())
2442 {
2443 36025 case safetyhook::ProcessCoordinator::Refusal::None:
2444 36025 m_refusal = CoordinatorHoldRefusal::None;
2445 36025 break;
2446 8 case safetyhook::ProcessCoordinator::Refusal::Timeout:
2447 8 m_refusal = CoordinatorHoldRefusal::Timeout;
2448 8 break;
2449 ✗ case safetyhook::ProcessCoordinator::Refusal::Poisoned:
2450 ✗ m_refusal = CoordinatorHoldRefusal::Poisoned;
2451 ✗ break;
2452 7 case safetyhook::ProcessCoordinator::Refusal::Incompatible:
2453 7 m_refusal = CoordinatorHoldRefusal::Incompatible;
2454 7 break;
2455 2 case safetyhook::ProcessCoordinator::Refusal::Unavailable:
2456 2 m_refusal = CoordinatorHoldRefusal::Unavailable;
2457 2 break;
2458 }
2459 36042 }
2460
2461 36036 BackendCoordinatorHold::~BackendCoordinatorHold() noexcept
2462 {
2463 36036 release();
2464 36036 }
2465
2466 36155 void BackendCoordinatorHold::release() noexcept
2467 {
2468
2/2
✓ Branch 2 → 3 taken 113 times.
✓ Branch 2 → 4 taken 36042 times.
36155 if (!m_constructed)
2469 {
2470 113 return;
2471 }
2472 36042 std::launder(reinterpret_cast<safetyhook::ProcessCoordinator *>(m_storage))->~ProcessCoordinator();
2473 36042 m_constructed = false;
2474 36042 m_held = false;
2475 }
2476 } // namespace detail
2477
2478 namespace hook
2479 {
2480 #if defined(DMK_ENABLE_TEST_SEAMS)
2481 16787 Hook::Impl::~Impl() noexcept
2482 {
2483 16787 DetourModKit::detail::note_hook_impl_destruction_for_test();
2484 16787 }
2485 #endif
2486
2487 34217 const std::shared_ptr<safetyhook::Allocator> &backend_allocator() noexcept
2488 {
2489 // Never-destroyed storage (`[B-47]`). The declaration states why the hold is never released. The backend
2490 // allocates its allocator, so a first-use failure publishes the latched empty hold (`[B-91]`).
2491 // Lifecycle.BackendAllocatorFirstUseOomFailsClosed pins the latch.
2492 alignas(
2493 std::shared_ptr<safetyhook::Allocator>
2494 ) static unsigned char storage[sizeof(std::shared_ptr<safetyhook::Allocator>)];
2495 static const std::shared_ptr<safetyhook::Allocator> *const allocator =
2496 1979 []() noexcept -> const std::shared_ptr<safetyhook::Allocator> *
2497 {
2498 try
2499 {
2500 1979 return ::new (static_cast<void *>(storage))
2501
4/6
✓ Branch 3 → 4 taken 1977 times.
✓ Branch 3 → 9 taken 2 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1977 times.
✓ Branch 9 → 10 taken 2 times.
✗ Branch 9 → 11 not taken.
1979 std::shared_ptr<safetyhook::Allocator>(safetyhook::Allocator::global());
2502 }
2503 2 catch (...)
2504 {
2505
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 2 times.
2 return ::new (static_cast<void *>(storage)) std::shared_ptr<safetyhook::Allocator>();
2506 2 }
2507
3/4
✓ Branch 2 → 3 taken 1979 times.
✓ Branch 2 → 8 taken 32238 times.
✓ Branch 4 → 5 taken 1979 times.
✗ Branch 4 → 8 not taken.
34217 }();
2508 34217 return *allocator;
2509 }
2510
2511 132502 Hook::GateSlot &Hook::gate_slot() noexcept
2512 {
2513 132502 return *std::launder(reinterpret_cast<GateSlot *>(m_gate_storage));
2514 }
2515
2516 103335 const Hook::GateSlot &Hook::gate_slot() const noexcept
2517 {
2518 103335 return *std::launder(reinterpret_cast<const GateSlot *>(m_gate_storage));
2519 }
2520
2521 // Hook is the RAII handle for one inline or mid hook.
2522 42130 Hook::Hook(std::unique_ptr<Impl> impl, std::shared_ptr<CallGate> gate) noexcept : m_impl(std::move(impl))
2523 {
2524
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 21065 times.
42130 ::new (static_cast<void *>(m_gate_storage)) GateSlot(std::move(gate));
2525 21065 }
2526
2527 78376 Hook::Hook(Hook &&other) noexcept : m_impl(std::move(other.m_impl))
2528 {
2529 // std::atomic is not movable. exchange leaves the source's gate empty, so a moved-from handle is fully
2530 // disengaged and fails closed.
2531 156752 ::new (static_cast<void *>(m_gate_storage))
2532
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 15 taken 39188 times.
39188 GateSlot(other.gate_slot().exchange(nullptr, std::memory_order_acq_rel));
2533 39188 }
2534
2535 4232 Hook &Hook::operator=(Hook &&other) noexcept
2536 {
2537
1/2
✓ Branch 2 → 3 taken 4232 times.
✗ Branch 2 → 18 not taken.
4232 if (this != &other)
2538 {
2539 // Adopt the current hook into a temporary whose ~Hook runs the loader-lock-aware teardown. A
2540 // concurrent call() that pinned this handle's gate keeps the old trampoline alive until it returns.
2541 4232 Hook discard(std::move(*this));
2542 8464 m_impl = std::move(other.m_impl);
2543 8464 gate_slot().store(
2544 8464 other.gate_slot().exchange(nullptr, std::memory_order_acq_rel),
2545 std::memory_order_release
2546 );
2547 4232 }
2548 4232 return *this;
2549 }
2550
2551 60251 Hook::~Hook() noexcept
2552 {
2553 60251 (void)detail::HookAccess::teardown(*this, detail::CountedDrainProof::Required);
2554 60251 }
2555
2556 62406 TeardownOutcome detail::HookAccess::teardown(
2557 Hook &hook,
2558 CountedDrainProof proof,
2559 std::vector<DeferredRestore> *deferred
2560 ) noexcept
2561 {
2562 62406 std::unique_ptr<Hook::Impl> &impl = hook.m_impl;
2563 // Take the gate reference out for the complete teardown. A pinned caller keeps the gate alive through its
2564 // own reference. A null callable below makes a late caller fail closed. The slot itself is never
2565 // destroyed, so a call() that races this teardown reads a valid null word.
2566 62406 std::shared_ptr<Hook::CallGate> gate = hook.gate_slot().exchange(nullptr, std::memory_order_acq_rel);
2567
2/2
✓ Branch 7 → 8 taken 45590 times.
✓ Branch 7 → 9 taken 16816 times.
62406 if (!impl)
2568 {
2569 45590 return TeardownOutcome::Empty;
2570 }
2571
2572 // Tombstone the mid-hook adapter before any teardown decision below. A late entrant exits at the adapter's
2573 // second live check. A pinned stub then becomes inert instead of a call to a destroyed owner. Inline hooks
2574 // have no slot. Their detour is the user function.
2575 16816 const std::size_t mid_slot = impl->mid_slot;
2576 16816 const bool has_mid_slot = mid_slot < DetourModKit::detail::MID_ADAPTER_CAPACITY;
2577
2/2
✓ Branch 10 → 11 taken 5252 times.
✓ Branch 10 → 13 taken 11564 times.
16816 if (has_mid_slot)
2578 {
2579 5252 DetourModKit::detail::mid_adapter_slots()[mid_slot].live.store(false, std::memory_order_seq_cst);
2580 }
2581
2582 // Loader-lock leaf discipline forbids a prologue restore, a drain, or backend destruction under the loader
2583 // lock. Each can deadlock, so leak the Impl instead. The detour stays reachable, so its module reference
2584 // stays held.
2585
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 18 taken 16816 times.
16816 if (!DetourModKit::detail::blocking_teardown_permitted())
2586 {
2587 ✗ diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
2588 ✗ (void)impl.release();
2589 ✗ return TeardownOutcome::Pinned;
2590 }
2591
2592 const DetourModKit::detail::MidRundown mid_rundown =
2593 has_mid_slot
2594
2/2
✓ Branch 18 → 19 taken 5252 times.
✓ Branch 18 → 21 taken 11564 times.
16816 ? DetourModKit::detail::run_down_mid_slot(DetourModKit::detail::mid_adapter_slots()[mid_slot])
2595 11564 : DetourModKit::detail::MidRundown::Drained;
2596
2597 16816 const std::uintptr_t target = impl->target;
2598 16816 const std::uint64_t ledger_id = impl->ledger_id;
2599 const diagnostics::HookKind kind =
2600
2/2
✓ Branch 25 → 26 taken 11564 times.
✓ Branch 25 → 27 taken 5252 times.
16816 impl->is_inline ? diagnostics::HookKind::Inline : diagnostics::HookKind::Mid;
2601 // Capture the armed state before the gate block below forces status to Disabled. Otherwise, the Removed
2602 // emission leaves the enable armed unit on the tally forever.
2603 16816 const bool was_active = impl->status.load(std::memory_order_acquire) == HookState::Active;
2604 // Copy the name out before reset() destroys its storage. The copy can throw under OOM inside a noexcept
2605 // destructor, so contain it and degrade to an empty name.
2606 16816 std::string name;
2607 try
2608 {
2609
2/2
✓ Branch 32 → 33 taken 16815 times.
✓ Branch 32 → 150 taken 1 time.
16816 name = impl->name;
2610 }
2611 1 catch (...)
2612 {
2613 1 }
2614
2615 // Serialize with any in-flight call() through the shared gate. A caller that owns the lock drains to
2616 // completion. A caller with only a pin reads the null callable under the same mutex and returns the
2617 // inactive default.
2618
1/2
✓ Branch 34 → 35 taken 16816 times.
✗ Branch 34 → 51 not taken.
16816 if (gate)
2619 {
2620 16816 std::unique_lock<std::recursive_mutex> guard = hook.acquire_call_lock(gate.get());
2621
1/2
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 42 taken 16816 times.
16816 if (!guard.owns_lock())
2622 {
2623 // An unowned guard makes restore safety unprovable. Leak the backend instead of a free of a
2624 // trampoline that a guarded caller can still use.
2625 ✗ diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
2626 ✗ (void)impl.release();
2627 ✗ return TeardownOutcome::Pinned;
2628 }
2629 16816 gate->callable = nullptr;
2630 16816 impl->status.store(HookState::Disabled, std::memory_order_release);
2631
1/2
✓ Branch 47 → 48 taken 16816 times.
✗ Branch 47 → 50 not taken.
16816 }
2632
2633 // A counted detour drains before the layer decision, so the wait holds no ledger slot (`[B-106]`).
2634
6/6
✓ Branch 53 → 54 taken 4389 times.
✓ Branch 53 → 56 taken 12427 times.
✓ Branch 54 → 55 taken 4249 times.
✓ Branch 54 → 56 taken 140 times.
✓ Branch 57 → 58 taken 4249 times.
✓ Branch 57 → 64 taken 12567 times.
16816 if (impl->counted && proof != CountedDrainProof::ProvenByRetire)
2635 {
2636
2/2
✓ Branch 62 → 63 taken 1 time.
✓ Branch 62 → 64 taken 4248 times.
4249 if (const char *const blocked = drain_counted_hook(impl->backend, *impl->counted))
2637 {
2638 1 return pin_backend_with_live_detour(impl, nullptr, name, target, ledger_id, kind, blocked);
2639 }
2640 }
2641 // A thread can still run a raw detour that a failed install arm made reachable, and no drain covers it.
2642
6/10
✓ Branch 66 → 67 taken 12427 times.
✓ Branch 66 → 74 taken 4388 times.
✓ Branch 68 → 69 taken 7175 times.
✓ Branch 68 → 74 taken 5252 times.
✗ Branch 69 → 70 not taken.
✓ Branch 69 → 74 taken 7175 times.
✗ Branch 72 → 73 not taken.
✗ Branch 72 → 74 not taken.
✗ Branch 75 → 76 not taken.
✓ Branch 75 → 78 taken 16815 times.
16815 if (!impl->counted && impl->is_inline && proof == CountedDrainProof::InstallRollback &&
2643 ✗ DetourModKit::detail::backend_committed(impl->backend))
2644 {
2645 ✗ return pin_backend_with_live_detour(
2646 impl,
2647 nullptr,
2648 name,
2649 target,
2650 ledger_id,
2651 kind,
2652 "no drain covers the raw detour of a failed install arm"
2653 ✗ );
2654 }
2655
2656 // Decide restore or retirement under this target's install-serialization slot. The slot makes the
2657 // decision atomic against a concurrent same-target install. Only the newest layer restores. A newer layer
2658 // relocated this hook's jump, so a lower layer and a claimed position retire by bypass (`[B-104]`).
2659 16815 auto &ledger = DetourModKit::detail::HookLedger::instance();
2660 16815 const std::size_t newer = ledger.acquire_target_slot(target, ledger_id);
2661
2/2
✓ Branch 80 → 81 taken 1 time.
✓ Branch 80 → 83 taken 16814 times.
16815 if (newer == DetourModKit::detail::HookLedger::SLOT_UNAVAILABLE)
2662 {
2663 1 return pin_backend_with_live_detour(
2664 impl,
2665 &ledger,
2666 name,
2667 target,
2668 ledger_id,
2669 kind,
2670 "the hook ledger cannot decide the layer order"
2671 1 );
2672 }
2673 // No layer chains to a patch that never committed, so such a hook releases under a newer layer too.
2674 16814 const bool committed = DetourModKit::detail::backend_committed(impl->backend);
2675
8/8
✓ Branch 85 → 86 taken 1050 times.
✓ Branch 85 → 87 taken 15764 times.
✓ Branch 86 → 87 taken 1027 times.
✓ Branch 86 → 90 taken 23 times.
✓ Branch 89 → 90 taken 703 times.
✓ Branch 89 → 91 taken 16088 times.
✓ Branch 92 → 93 taken 726 times.
✓ Branch 92 → 97 taken 16088 times.
16814 if ((newer > 0 && committed) || DetourModKit::detail::backend_claimed(impl->backend))
2676 {
2677 1452 return retire_by_vacate(
2678 impl,
2679 ledger,
2680 name,
2681 target,
2682 ledger_id,
2683 kind,
2684 was_active,
2685 mid_rundown,
2686 has_mid_slot,
2687 mid_slot,
2688 RetirementCause{.newer_layers = newer}
2689 726 );
2690 }
2691
2692 16088 RetirementCause cause{};
2693 16088 TeardownRestore restore = TeardownRestore::Restored;
2694
2/2
✓ Branch 97 → 98 taken 10434 times.
✓ Branch 97 → 99 taken 5654 times.
16088 if (committed)
2695 {
2696 10434 restore = restore_target_or_pin_backend(impl, ledger, name, target, ledger_id, kind, cause);
2697 }
2698 else
2699 {
2700 11308 (void)apply_backend(impl->backend, [](auto &backend) noexcept { backend.finish_route_rundown(); });
2701 }
2702
2/2
✓ Branch 102 → 103 taken 10 times.
✓ Branch 102 → 104 taken 16078 times.
16088 if (restore == TeardownRestore::Pinned)
2703 {
2704 10 return TeardownOutcome::Pinned;
2705 }
2706
2/2
✓ Branch 104 → 105 taken 65 times.
✓ Branch 104 → 107 taken 16013 times.
16078 if (restore == TeardownRestore::Retire)
2707 {
2708 65 return retire_by_vacate(
2709 impl,
2710 ledger,
2711 name,
2712 target,
2713 ledger_id,
2714 kind,
2715 was_active,
2716 mid_rundown,
2717 has_mid_slot,
2718 mid_slot,
2719 cause
2720 65 );
2721 }
2722
2723
2/2
✓ Branch 108 → 109 taken 13 times.
✓ Branch 108 → 110 taken 16000 times.
16013 if (!drain_route_or_retain_backend(impl, ledger, name, target, ledger_id, kind, was_active, mid_rundown))
2724 {
2725 13 return TeardownOutcome::Pinned;
2726 }
2727
2728
4/4
✓ Branch 110 → 111 taken 5159 times.
✓ Branch 110 → 115 taken 10841 times.
✓ Branch 116 → 117 taken 2 times.
✓ Branch 116 → 119 taken 15998 times.
21159 if (has_mid_slot &&
2729
2/2
✓ Branch 113 → 114 taken 2 times.
✓ Branch 113 → 115 taken 5157 times.
5159 !DetourModKit::detail::drain_mid_adapter_entries(DetourModKit::detail::mid_adapter_slots()[mid_slot]))
2730 {
2731 2 retain_backend_for_busy_adapter(impl, ledger, name, target, ledger_id, kind, was_active);
2732 2 return TeardownOutcome::Pinned;
2733 }
2734
2735 // The reserved capacity keeps the push free of allocation.
2736
3/4
✓ Branch 119 → 120 taken 2134 times.
✓ Branch 119 → 124 taken 13864 times.
✓ Branch 122 → 123 taken 2134 times.
✗ Branch 122 → 124 not taken.
15998 const bool defer = deferred != nullptr && deferred->size() < deferred->capacity();
2737
2/2
✓ Branch 127 → 128 taken 123 times.
✓ Branch 127 → 142 taken 15875 times.
15998 if (DetourModKit::detail::release_backend(impl->backend, defer))
2738 {
2739 123 (void)ledger.release_hook(target, ledger_id);
2740 123 deferred->push_back(
2741
2/4
✗ Branch 137 → 138 not taken.
✓ Branch 137 → 139 taken 123 times.
✗ Branch 139 → 140 not taken.
✓ Branch 139 → 141 taken 123 times.
246 DeferredRestore{
2742 123 .impl = std::move(impl),
2743 123 .name = std::move(name),
2744 .was_active = was_active,
2745 }
2746 );
2747 123 return TeardownOutcome::Deferred;
2748 }
2749 const TeardownOutcome reclaimed =
2750 15875 reclaim_restored_backend(impl, &ledger, name, target, ledger_id, has_mid_slot, mid_slot);
2751 15875 emit_lifecycle(
2752 name,
2753 ledger_id,
2754 kind,
2755 diagnostics::HookTransition::Removed,
2756 RemovalPopulationState{
2757 .was_active = was_active,
2758 }
2759 );
2760 15875 return reclaimed;
2761 62406 }
2762
2763 123 TeardownOutcome detail::HookAccess::finish_deferred_restore(DeferredRestore &restore) noexcept
2764 {
2765 123 const std::uintptr_t target = restore.impl->target;
2766 123 const std::uint64_t ledger_id = restore.impl->ledger_id;
2767 123 const std::size_t mid_slot = restore.impl->mid_slot;
2768 const diagnostics::HookKind kind =
2769
2/2
✓ Branch 6 → 7 taken 118 times.
✓ Branch 6 → 8 taken 5 times.
123 restore.impl->is_inline ? diagnostics::HookKind::Inline : diagnostics::HookKind::Mid;
2770 123 const TeardownOutcome reclaimed = reclaim_restored_backend(
2771 123 restore.impl,
2772 nullptr,
2773 123 restore.name,
2774 target,
2775 ledger_id,
2776 mid_slot < DetourModKit::detail::MID_ADAPTER_CAPACITY,
2777 mid_slot
2778 );
2779 123 emit_lifecycle(
2780 restore.name,
2781 ledger_id,
2782 kind,
2783 diagnostics::HookTransition::Removed,
2784 RemovalPopulationState{
2785 123 .was_active = restore.was_active,
2786 }
2787 );
2788 123 return reclaimed;
2789 }
2790
2791 22 Hook::operator bool() const noexcept
2792 {
2793 22 return m_impl != nullptr;
2794 }
2795
2796 5 std::string_view Hook::name() const noexcept
2797 {
2798
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 6 not taken.
5 return m_impl ? std::string_view{m_impl->name} : std::string_view{};
2799 }
2800
2801 5767 bool Hook::is_enabled() const noexcept
2802 {
2803 5767 const std::shared_ptr<CallGate> gate = gate_slot().load(std::memory_order_acquire);
2804
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 5766 times.
5767 if (!gate)
2805 {
2806 ✗ return false;
2807 }
2808 5766 std::unique_lock<std::recursive_mutex> guard = acquire_call_lock(gate.get());
2809
3/6
✓ Branch 10 → 11 taken 5767 times.
✗ Branch 10 → 13 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 5767 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 5767 times.
5767 if (!guard.owns_lock() || !m_impl)
2810 {
2811 ✗ return false;
2812 }
2813 // Both the published state and the reconciled backend view must agree. The gate serializes this read
2814 // with every backend flag update.
2815
3/4
✓ Branch 19 → 20 taken 4804 times.
✓ Branch 19 → 24 taken 963 times.
✓ Branch 22 → 23 taken 4804 times.
✗ Branch 22 → 24 not taken.
10571 return m_impl->status.load(std::memory_order_acquire) == HookState::Active &&
2816 4804 backend_value_or(
2817 4804 m_impl->backend,
2818 false,
2819
4/8
auto DetourModKit::hook::Hook::is_enabled() const::{lambda(auto:1&)#1}::operator()<safetyhook::InlineHook>(safetyhook::InlineHook&) const:
✓ Branch 3 → 4 taken 4783 times.
✗ Branch 3 → 7 not taken.
✓ Branch 5 → 6 taken 4783 times.
✗ Branch 5 → 7 not taken.
auto DetourModKit::hook::Hook::is_enabled() const::{lambda(auto:1&)#1}::operator()<safetyhook::MidHook>(safetyhook::MidHook&) const:
✓ Branch 3 → 4 taken 21 times.
✗ Branch 3 → 7 not taken.
✓ Branch 5 → 6 taken 21 times.
✗ Branch 5 → 7 not taken.
10571 [](auto &backend) noexcept { return static_cast<bool>(backend) && backend.enabled(); }
2820 5767 );
2821 5767 }
2822
2823 3667 void *Hook::original_address() const noexcept
2824 {
2825 // The original<Fn>() path uses no gate or atomic shared-pointer load. The caller guarantees that the hook
2826 // outlives the call.
2827
2/2
✓ Branch 3 → 4 taken 3666 times.
✓ Branch 3 → 6 taken 1 time.
3667 return m_impl ? inline_trampoline(m_impl->backend) : nullptr;
2828 }
2829
2830 97569 std::shared_ptr<Hook::CallGate> Hook::pin_call_gate() const noexcept
2831 {
2832 // Copy the gate reference atomically into a strong local. call() can then keep the trampoline and mutex
2833 // alive across a concurrent teardown that drops the handle's own reference.
2834 97569 return gate_slot().load(std::memory_order_acquire);
2835 }
2836
2837 67612 std::unique_lock<std::recursive_mutex> Hook::acquire_call_lock(CallGate *gate) const noexcept
2838 {
2839 try
2840 {
2841
1/2
✓ Branch 2 → 3 taken 67615 times.
✗ Branch 2 → 5 not taken.
67612 return std::unique_lock<std::recursive_mutex>(gate->mutex);
2842 }
2843 ✗ catch (...)
2844 {
2845 // recursive_mutex::lock can throw std::system_error. Fail closed: an unowned lock makes call()
2846 // return the inactive default.
2847 ✗ return std::unique_lock<std::recursive_mutex>{};
2848 ✗ }
2849 }
2850
2851 22601 void *Hook::active_trampoline(CallGate *gate) const noexcept
2852 {
2853 // Every writer publishes gate->callable under the mutex the caller already holds, so this observes the
2854 // live trampoline or nullptr, never a stale pointer.
2855 22601 return gate->callable;
2856 }
2857
2858 13 void Hook::release() noexcept
2859 {
2860
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 13 times.
13 if (!m_impl)
2861 {
2862 ✗ return;
2863 }
2864 // Leak the backend hook intentionally: it stays installed for the process lifetime and the ledger entry
2865 // stays so is_target_hooked still reports it. A gate clear disengages the handle, which matches the
2866 // moved-from contract. The ledger records it like every defensive pin in ~Hook.
2867 13 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
2868 13 (void)m_impl.release();
2869 13 gate_slot().store(nullptr, std::memory_order_release);
2870 }
2871
2872 namespace
2873 {
2874 /**
2875 * @brief Checks the backend allocator and takes the module reference of an install on @p reserved.
2876 * @return The module reference, or the Error after the reservation rolled back.
2877 */
2878 [[nodiscard]] Result<HMODULE>
2879 16949 acquire_install_module_ref(const detail::ReservedTarget &reserved, const char *where) noexcept
2880 {
2881
2/2
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 10 taken 16945 times.
16949 if (!backend_allocator())
2882 {
2883 4 (void)DetourModKit::detail::HookLedger::instance().release_hook(
2884 4 reserved.address,
2885 4 reserved.ledger_id
2886 );
2887 4 return std::unexpected(Error{ErrorCode::AllocatorNotAvailable, where});
2888 }
2889 16945 const HMODULE module = acquire_hook_self_ref();
2890
2/2
✓ Branch 11 → 12 taken 3 times.
✓ Branch 11 → 18 taken 16942 times.
16945 if (module == nullptr)
2891 {
2892 // Capture the acquire's last-error before release_hook can clobber it (error.hpp documents
2893 // SystemCallFailed's detail = GetLastError()).
2894 3 const DWORD acquire_error = ::GetLastError();
2895 3 (void)DetourModKit::detail::HookLedger::instance().release_hook(
2896 3 reserved.address,
2897 3 reserved.ledger_id
2898 );
2899 3 return std::unexpected(Error{ErrorCode::SystemCallFailed, where, acquire_error});
2900 }
2901 16942 return module;
2902 }
2903
2904 /**
2905 * @brief Decodes the counted thunk of @p install for its drain proof, or rolls @p reserved back.
2906 * @return The thunk, or InvalidDetourFunction after one log line that names the cause.
2907 */
2908 4417 [[nodiscard]] Result<CountedThunk> inspect_counted_install(
2909 std::string_view name,
2910 const detail::CountedInstall &install,
2911 const detail::ReservedTarget &reserved
2912 )
2913 {
2914 const std::expected<detail::CountedThunkShape, const char *> shape =
2915 4417 detail::inspect_counted_thunk(install.entry);
2916
5/6
✓ Branch 4 → 5 taken 4409 times.
✓ Branch 4 → 6 taken 8 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 4409 times.
✓ Branch 8 → 9 taken 8 times.
✓ Branch 8 → 21 taken 4409 times.
4417 if (!shape || install.block == nullptr)
2917 {
2918 8 (void)DetourModKit::detail::HookLedger::instance().release_hook(
2919 8 reserved.address,
2920 8 reserved.ledger_id
2921 );
2922 8 (void)log().try_log(
2923 LogLevel::Error,
2924 "hook::inline_at: the counted thunk of '{}' has a shape that the drain proof cannot cover: {}.",
2925 name,
2926
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 8 times.
8 shape ? "it has no counters" : shape.error()
2927 );
2928 8 return std::unexpected(Error{ErrorCode::InvalidDetourFunction, "hook::inline_at"});
2929 }
2930
2/2
✓ Branch 22 → 23 taken 24 times.
✓ Branch 22 → 27 taken 4385 times.
4409 if (shape->helper_calls != 0)
2931 {
2932 48 (void)log().try_log(
2933 LogLevel::Warning,
2934 "hook::inline_at: the counted thunk of '{}' calls {} helper(s) outside its counted window, so "
2935 "its drain also reads thread stacks. A stale stack copy of a helper return can keep a "
2936 "retirement Busy.",
2937 name,
2938 24 shape->helper_calls
2939 );
2940 }
2941 4409 CountedThunk thunk = shape->thunk;
2942 4409 thunk.block = install.block;
2943 4409 return thunk;
2944 }
2945
2946 /// Creates the disabled inline backend hook at @p target whose relay jumps to @p destination.
2947 [[nodiscard]] std::expected<safetyhook::InlineHook, safetyhook::InlineHook::Error>
2948 11642 create_inline_backend(std::uintptr_t target, void *destination, std::string_view name)
2949 {
2950 return safetyhook::InlineHook::create(
2951 backend_allocator(),
2952 reinterpret_cast<void *>(target),
2953 destination,
2954 safetyhook::InlineHook::StartDisabled,
2955 position_claim_for(name)
2956 11642 );
2957 }
2958
2959 /// Creates the disabled mid backend hook at @p target that enters the adapter of @p slot_index.
2960 [[nodiscard]] std::expected<safetyhook::MidHook, safetyhook::MidHook::Error>
2961 5266 create_mid_backend(std::uintptr_t target, std::size_t slot_index, std::string_view name)
2962 {
2963 return safetyhook::MidHook::create(
2964 backend_allocator(),
2965 reinterpret_cast<void *>(target),
2966 5266 DetourModKit::detail::MID_ADAPTER_TABLE[slot_index],
2967 safetyhook::MidHook::StartDisabled,
2968 position_claim_for(name)
2969 10532 );
2970 }
2971 } // namespace
2972
2973 9444 Result<Hook> detail::HookAccess::install_inline(
2974 InlineRequest request,
2975 const ReservedTarget &reserved,
2976 void *destination,
2977 std::optional<CountedThunk> counted
2978 )
2979 {
2980 9444 const std::uintptr_t target = reserved.address;
2981 9444 const std::uint64_t ledger_id = reserved.ledger_id;
2982 9444 const Result<HMODULE> module = acquire_install_module_ref(reserved, "hook::inline_at");
2983
2/2
✓ Branch 4 → 5 taken 5 times.
✓ Branch 4 → 9 taken 9439 times.
9444 if (!module)
2984 {
2985 5 return std::unexpected(module.error());
2986 }
2987 9439 ModuleRefGuard self_ref(*module);
2988 try
2989 {
2990 // StartDisabled makes this an install transaction. The detour stays unreachable while the fallible
2991 // steps below publish the caller state. No fault boundary wraps this code. See
2992 // hook_fault_boundary.hpp.
2993 9439 std::optional<DetourModKit::detail::BackendCoordinatorHold> hold;
2994 9439 ClassificationLog lines;
2995 Result<safetyhook::InlineHook> created = create_backend_under_coordinator(
2996 reserved,
2997 9439 request.options,
2998 request.name,
2999 "hook::inline_at",
3000 hold,
3001 lines,
3002 9449 [&]() { return create_inline_backend(target, destination, request.name); }
3003
2/2
✓ Branch 12 → 13 taken 9401 times.
✓ Branch 12 → 80 taken 38 times.
9439 );
3004
2/2
✓ Branch 14 → 15 taken 30 times.
✓ Branch 14 → 19 taken 9371 times.
9401 if (!created)
3005 {
3006 30 return std::unexpected(created.error());
3007 }
3008 9371 hold.reset();
3009 9371 lines.emit("hook::inline_at", request.name, target);
3010
1/2
✓ Branch 23 → 24 taken 9371 times.
✗ Branch 23 → 92 not taken.
18742 auto backend_hook = std::move(created.value());
3011 #if defined(DMK_ENABLE_TEST_SEAMS)
3012
2/2
✓ Branch 27 → 28 taken 9354 times.
✓ Branch 27 → 90 taken 17 times.
9371 note_publish_step(DetourModKit::detail::HookPublishStep::BackendCreated);
3013 #endif
3014 9354 const bool claimed = backend_hook.claimed();
3015 auto impl = std::make_unique<Hook::Impl>(
3016 9354 std::move(backend_hook),
3017 9354 std::move(request.name),
3018 target,
3019 ledger_id,
3020 9355 HookState::Disabled
3021
2/2
✓ Branch 33 → 34 taken 9353 times.
✓ Branch 33 → 81 taken 1 time.
9354 );
3022 9353 impl->bypassed = claimed;
3023 9353 impl->counted = counted;
3024 #if defined(DMK_ENABLE_TEST_SEAMS)
3025
2/2
✓ Branch 36 → 37 taken 9352 times.
✓ Branch 36 → 88 taken 1 time.
9353 note_publish_step(DetourModKit::detail::HookPublishStep::ImplConstructed);
3026 #endif
3027 // The gate starts null-callable, exactly as disable() leaves it. enable() publishes the
3028 // trampoline once the target is armed.
3029
2/2
✓ Branch 37 → 38 taken 9351 times.
✓ Branch 37 → 88 taken 1 time.
9352 auto gate = std::make_shared<Hook::CallGate>();
3030 #if defined(DMK_ENABLE_TEST_SEAMS)
3031
2/2
✓ Branch 38 → 39 taken 9350 times.
✓ Branch 38 → 86 taken 1 time.
9351 note_publish_step(DetourModKit::detail::HookPublishStep::GatePublished);
3032 #endif
3033 9350 const std::string_view created_name = impl->name;
3034
2/2
✓ Branch 43 → 44 taken 1 time.
✓ Branch 43 → 49 taken 9349 times.
9350 if (!DetourModKit::detail::HookLedger::instance().commit_hook(target, ledger_id))
3035 {
3036 1 (void)DetourModKit::detail::HookLedger::instance().release_hook(target, ledger_id);
3037 1 return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::inline_at", target});
3038 }
3039
1/2
✓ Branch 51 → 52 taken 9348 times.
✗ Branch 51 → 82 not taken.
18697 log().info(
3040 "hook::inline_at: created inline hook '{}' at {} (disabled).",
3041 created_name,
3042
2/2
✓ Branch 50 → 51 taken 9348 times.
✓ Branch 50 → 85 taken 1 time.
18697 format::format_address(target)
3043 );
3044
2/2
✓ Branch 53 → 54 taken 637 times.
✓ Branch 53 → 55 taken 8711 times.
9348 if (claimed)
3045 {
3046 637 note_position_claim(created_name, target);
3047 }
3048 #if defined(DMK_ENABLE_TEST_SEAMS)
3049
2/2
✓ Branch 55 → 56 taken 9347 times.
✓ Branch 55 → 86 taken 1 time.
9348 note_publish_step(DetourModKit::detail::HookPublishStep::LedgerCommitted);
3050 #endif
3051 9347 emit_lifecycle(
3052 created_name,
3053 ledger_id,
3054 diagnostics::HookKind::Inline,
3055 diagnostics::HookTransition::Created
3056 );
3057 // Hand the module reference to the Impl only after completion of every fallible setup step.
3058 9347 impl->self_ref = self_ref.release();
3059 18694 return make(std::move(impl), std::move(gate));
3060 9493 }
3061
1/2
✓ Branch 97 → 98 taken 61 times.
✗ Branch 97 → 104 not taken.
61 catch (const std::bad_alloc &)
3062 {
3063 61 (void)DetourModKit::detail::HookLedger::instance().release_hook(target, ledger_id);
3064 61 return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::inline_at", target});
3065 61 }
3066 ✗ catch (...)
3067 {
3068 ✗ (void)DetourModKit::detail::HookLedger::instance().release_hook(target, ledger_id);
3069 ✗ return std::unexpected(Error{ErrorCode::UnknownError, "hook::inline_at", target});
3070
0/2
✗ Branch 109 → 77 not taken.
✗ Branch 109 → 110 not taken.
✗ }
3071 9439 }
3072
3073 namespace detail
3074 {
3075 7293 Result<Hook> inline_at_raw(InlineRequest request, void *detour)
3076 {
3077 7293 Result<ReservedTarget> preflight = preflight_inline_request(request, detour);
3078
2/2
✓ Branch 4 → 5 taken 27 times.
✓ Branch 4 → 9 taken 7266 times.
7293 if (!preflight)
3079 {
3080 27 return std::unexpected(preflight.error());
3081 }
3082
1/2
✓ Branch 14 → 15 taken 7266 times.
✗ Branch 14 → 20 not taken.
14532 return HookAccess::install_inline(std::move(request), *preflight, detour, std::nullopt);
3083 }
3084
3085 2194 Result<Hook> inline_at_counted(InlineRequest request, CountedInstall install)
3086 {
3087 2194 Result<ReservedTarget> preflight = preflight_inline_request(request, install.entry);
3088
2/2
✓ Branch 4 → 5 taken 8 times.
✓ Branch 4 → 9 taken 2186 times.
2194 if (!preflight)
3089 {
3090 8 return std::unexpected(preflight.error());
3091 }
3092 2186 const Result<CountedThunk> thunk = inspect_counted_install(request.name, install, *preflight);
3093
2/2
✓ Branch 13 → 14 taken 8 times.
✓ Branch 13 → 18 taken 2178 times.
2186 if (!thunk)
3094 {
3095 8 return std::unexpected(thunk.error());
3096 }
3097
1/2
✓ Branch 25 → 26 taken 2178 times.
✗ Branch 25 → 31 not taken.
4356 return HookAccess::install_inline(std::move(request), *preflight, thunk->range.begin, *thunk);
3098 }
3099 } // namespace detail
3100
3101 3277 Result<Hook> mid_at(MidRequest request, MidHookFn detour)
3102 {
3103 3277 Result<detail::ReservedTarget> preflight = preflight_mid_request(request, detour);
3104
2/2
✓ Branch 4 → 5 taken 7 times.
✓ Branch 4 → 9 taken 3270 times.
3277 if (!preflight)
3105 {
3106 7 return std::unexpected(preflight.error());
3107 }
3108 3270 const std::uintptr_t target = preflight->address;
3109 // Every failure path below rolls back this reservation. Success commits it after all fallible setup.
3110 3270 const std::uint64_t ledger_id = preflight->ledger_id;
3111
3112 3270 const Result<HMODULE> module = acquire_install_module_ref(*preflight, "hook::mid_at");
3113
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 19 taken 3269 times.
3270 if (!module)
3114 {
3115 1 return std::unexpected(module.error());
3116 }
3117 3269 ModuleRefGuard self_ref(*module);
3118 3269 const Result<std::size_t> claim = claim_mid_adapter_for_install(target, ledger_id, detour);
3119
2/2
✓ Branch 23 → 24 taken 2 times.
✓ Branch 23 → 28 taken 3267 times.
3269 if (!claim)
3120 {
3121 2 return std::unexpected(claim.error());
3122 }
3123 3267 const std::size_t slot_index = *claim;
3124 3267 MidAdapterSlotGuard slot_guard(slot_index);
3125 try
3126 {
3127 // This is the StartDisabled install transaction. See inline_at_raw and hook_fault_boundary.hpp. The
3128 // destination is the pool slot_index adapter, a real void(safetyhook::Context&).
3129 3267 std::optional<DetourModKit::detail::BackendCoordinatorHold> hold;
3130 3267 ClassificationLog lines;
3131 Result<safetyhook::MidHook> created = create_backend_under_coordinator(
3132 3267 *preflight,
3133 3267 request.options,
3134 request.name,
3135 "hook::mid_at",
3136 hold,
3137 lines,
3138 3265 [&]() { return create_mid_backend(target, slot_index, request.name); }
3139
1/2
✓ Branch 32 → 33 taken 3267 times.
✗ Branch 32 → 102 not taken.
6534 );
3140
2/2
✓ Branch 34 → 35 taken 10 times.
✓ Branch 34 → 39 taken 3257 times.
3267 if (!created)
3141 {
3142 10 return std::unexpected(created.error());
3143 }
3144 3257 hold.reset();
3145 3257 lines.emit("hook::mid_at", request.name, target);
3146
1/2
✓ Branch 43 → 44 taken 3257 times.
✗ Branch 43 → 114 not taken.
6514 auto backend_hook = std::move(created.value());
3147 #if defined(DMK_ENABLE_TEST_SEAMS)
3148
2/2
✓ Branch 47 → 48 taken 3256 times.
✓ Branch 47 → 112 taken 1 time.
3257 note_publish_step(DetourModKit::detail::HookPublishStep::BackendCreated);
3149 #endif
3150 3256 const bool claimed = backend_hook.claimed();
3151 auto impl = std::make_unique<Hook::Impl>(
3152 3256 std::move(backend_hook),
3153 3256 std::move(request.name),
3154 target,
3155 ledger_id,
3156 3256 HookState::Disabled
3157
1/2
✓ Branch 53 → 54 taken 3256 times.
✗ Branch 53 → 103 not taken.
3256 );
3158 3256 impl->bypassed = claimed;
3159 #if defined(DMK_ENABLE_TEST_SEAMS)
3160
2/2
✓ Branch 55 → 56 taken 3255 times.
✓ Branch 55 → 110 taken 1 time.
3256 note_publish_step(DetourModKit::detail::HookPublishStep::ImplConstructed);
3161 #endif
3162 // A mid hook gate is null-callable for life. It still serializes enable, disable, and teardown.
3163
1/2
✓ Branch 56 → 57 taken 3255 times.
✗ Branch 56 → 110 not taken.
3255 auto gate = std::make_shared<Hook::CallGate>();
3164 #if defined(DMK_ENABLE_TEST_SEAMS)
3165
2/2
✓ Branch 57 → 58 taken 3254 times.
✓ Branch 57 → 108 taken 1 time.
3255 note_publish_step(DetourModKit::detail::HookPublishStep::GatePublished);
3166 #endif
3167 3254 const std::string_view created_name = impl->name;
3168
1/2
✗ Branch 62 → 63 not taken.
✓ Branch 62 → 68 taken 3254 times.
3254 if (!DetourModKit::detail::HookLedger::instance().commit_hook(target, ledger_id))
3169 {
3170 ✗ (void)DetourModKit::detail::HookLedger::instance().release_hook(target, ledger_id);
3171 ✗ return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::mid_at", target});
3172 }
3173
1/2
✓ Branch 70 → 71 taken 3254 times.
✗ Branch 70 → 104 not taken.
6508 log().info(
3174 "hook::mid_at: created mid hook '{}' at {} (disabled).",
3175 created_name,
3176
1/2
✓ Branch 69 → 70 taken 3254 times.
✗ Branch 69 → 107 not taken.
6508 format::format_address(target)
3177 );
3178
2/2
✓ Branch 72 → 73 taken 67 times.
✓ Branch 72 → 74 taken 3187 times.
3254 if (claimed)
3179 {
3180 67 note_position_claim(created_name, target);
3181 }
3182 #if defined(DMK_ENABLE_TEST_SEAMS)
3183
2/2
✓ Branch 74 → 75 taken 3253 times.
✓ Branch 74 → 108 taken 1 time.
3254 note_publish_step(DetourModKit::detail::HookPublishStep::LedgerCommitted);
3184 #endif
3185 3253 emit_lifecycle(
3186 created_name,
3187 ledger_id,
3188 diagnostics::HookKind::Mid,
3189 diagnostics::HookTransition::Created
3190 );
3191 // Hand the module reference and adapter slot to the Impl. Teardown owns both after this point.
3192 3253 impl->self_ref = self_ref.release();
3193 3253 impl->mid_slot = slot_guard.release();
3194 6506 return Hook(std::move(impl), std::move(gate));
3195 3280 }
3196
1/2
✓ Branch 119 → 120 taken 4 times.
✗ Branch 119 → 126 not taken.
4 catch (const std::bad_alloc &)
3197 {
3198 4 (void)DetourModKit::detail::HookLedger::instance().release_hook(target, ledger_id);
3199 4 return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::mid_at", target});
3200 4 }
3201 ✗ catch (...)
3202 {
3203 ✗ (void)DetourModKit::detail::HookLedger::instance().release_hook(target, ledger_id);
3204 ✗ return std::unexpected(Error{ErrorCode::UnknownError, "hook::mid_at", target});
3205
0/2
✗ Branch 131 → 98 not taken.
✗ Branch 131 → 132 not taken.
✗ }
3206 3269 }
3207
3208 template <class Backend, class CreateBackend, class HandOff>
3209 4234 Result<std::reference_wrapper<Hook>> detail::HookAccess::install_into_stack(
3210 std::vector<std::unique_ptr<Hook>> &hooks,
3211 std::string name,
3212 const ReservedTarget &reserved,
3213 const Options &options,
3214 const OriginalSlot &original,
3215 CreateBackend &&create_backend,
3216 HandOff &&hand_off
3217 ) noexcept
3218 {
3219 4234 constexpr bool is_inline = std::is_same_v<Backend, safetyhook::InlineHook>;
3220 4234 const char *const where = is_inline ? "hook::inline_at" : "hook::mid_at";
3221 4234 const std::uintptr_t target = reserved.address;
3222 4235 const auto roll_back = [&reserved, where](ErrorCode code) noexcept -> Error
3223 {
3224 1 (void)DetourModKit::detail::HookLedger::instance().release_hook(reserved.address, reserved.ledger_id);
3225 1 return Error{code, where, reserved.address};
3226 };
3227
3228 4234 std::unique_ptr<Hook> entry;
3229 4234 std::shared_ptr<Hook::CallGate> gate;
3230 4234 std::unique_ptr<Hook::Impl> impl;
3231 4234 DetourModKit::detail::LifecycleSnapshot snapshot;
3232 try
3233 {
3234
4/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 5 → 6 taken 230 times.
✓ Branch 5 → 10 taken 2003 times.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 10 taken 2000 times.
4234 if (hooks.size() == hooks.capacity())
3235 {
3236
2/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 8 → 9 taken 230 times.
✗ Branch 8 → 147 not taken.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 147 not taken.
231 hooks.reserve(std::max<std::size_t>(4, hooks.size() * 2));
3237 }
3238
2/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 13 → 14 taken 2233 times.
✗ Branch 13 → 149 not taken.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✓ Branch 13 → 14 taken 2001 times.
✗ Branch 13 → 149 not taken.
4234 entry = std::make_unique<Hook>(make(nullptr, nullptr));
3239
2/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 19 → 20 taken 2233 times.
✗ Branch 19 → 159 not taken.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✓ Branch 19 → 20 taken 2001 times.
✗ Branch 19 → 159 not taken.
4234 gate = std::make_shared<Hook::CallGate>();
3240
2/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 22 → 23 taken 2233 times.
✗ Branch 22 → 165 not taken.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✓ Branch 22 → 23 taken 2001 times.
✗ Branch 22 → 165 not taken.
4234 snapshot.name = name;
3241 4234 snapshot.ledger_id = reserved.ledger_id;
3242 4234 snapshot.kind = is_inline ? diagnostics::HookKind::Inline : diagnostics::HookKind::Mid;
3243
2/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 26 → 27 taken 2233 times.
✗ Branch 26 → 160 not taken.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✓ Branch 26 → 27 taken 2001 times.
✗ Branch 26 → 160 not taken.
4234 impl = std::make_unique<Hook::Impl>(
3244 Backend{},
3245 4234 std::move(name),
3246 target,
3247 4234 reserved.ledger_id,
3248 4234 HookState::Disabled
3249 );
3250 }
3251
0/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✗ Branch 165 → 166 not taken.
✗ Branch 165 → 171 not taken.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✗ Branch 165 → 166 not taken.
✗ Branch 165 → 171 not taken.
✗ catch (const std::bad_alloc &)
3252 {
3253 ✗ return std::unexpected(roll_back(ErrorCode::OutOfMemory));
3254 }
3255 ✗ catch (...)
3256 {
3257 ✗ return std::unexpected(roll_back(ErrorCode::UnknownError));
3258 }
3259
3260 4234 std::optional<DetourModKit::detail::BackendCoordinatorHold> hold;
3261 4234 ClassificationLog lines;
3262 8468 Result<Backend> created = [&]() noexcept -> Result<Backend>
3263 {
3264 try
3265 {
3266 return create_backend_under_coordinator(
3267 reserved,
3268 options,
3269 4234 snapshot.name,
3270 where,
3271 hold,
3272 lines,
3273 8466 [&]() { return create_backend(std::string_view{snapshot.name}); }
3274
1/2
✓ Branch 3 → 4 taken 4234 times.
✗ Branch 3 → 7 not taken.
4234 );
3275 }
3276
0/2
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 15 not taken.
✗ catch (const std::bad_alloc &)
3277 {
3278 ✗ hold.reset();
3279 ✗ return std::unexpected(roll_back(ErrorCode::OutOfMemory));
3280 }
3281 ✗ catch (...)
3282 {
3283 ✗ hold.reset();
3284 ✗ return std::unexpected(roll_back(ErrorCode::UnknownError));
3285 }
3286 }();
3287
3/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 32 → 33 taken 2 times.
✓ Branch 32 → 37 taken 2231 times.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 37 taken 2001 times.
4234 if (!created)
3288 {
3289 2 return std::unexpected(created.error());
3290 }
3291 4232 const bool claimed = created->claimed();
3292 8464 impl->backend = std::move(*created);
3293 4232 impl->bypassed = claimed;
3294
3/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 47 → 48 taken 1 time.
✓ Branch 47 → 56 taken 2230 times.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 56 taken 2001 times.
4232 if (!DetourModKit::detail::HookLedger::instance().commit_hook_keep_slot(target, reserved.ledger_id))
3295 {
3296 1 hold.reset();
3297 1 lines.emit(where, snapshot.name, target);
3298 1 return std::unexpected(roll_back(ErrorCode::OutOfMemory));
3299 }
3300 // The arm moves the enabled tally, so the created tally moves first.
3301 4231 DetourModKit::detail::hook_population::record_created(false);
3302 4231 hand_off(*impl);
3303 4231 void *const trampoline = inline_trampoline(impl->backend);
3304 8462 *entry = make(std::move(impl), std::move(gate));
3305 4231 Hook &stored = *hooks.emplace_back(std::move(entry));
3306 4231 publish_original(original, trampoline);
3307 4231 DeferredArm deferred;
3308 4231 const Result<void> armed = arm_installed(stored, deferred);
3309 4231 hold.reset();
3310 4231 DetourModKit::detail::HookLedger::instance().release_target_slot(target, reserved.ledger_id);
3311
3312 4231 lines.emit(where, snapshot.name, target);
3313
3/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 91 → 92 taken 2227 times.
✓ Branch 91 → 93 taken 3 times.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✓ Branch 91 → 92 taken 2001 times.
✗ Branch 91 → 93 not taken.
8462 (void)log().try_log(
3314 4231 armed ? LogLevel::Info : LogLevel::Warning,
3315 "{}: created {} hook '{}' at 0x{:0{}X}{}.",
3316 where,
3317 8462 is_inline ? "inline" : "mid",
3318 snapshot.name,
3319 target,
3320 8462 sizeof(std::uintptr_t) * 2,
3321
3/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 87 → 88 taken 2227 times.
✓ Branch 87 → 89 taken 3 times.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✓ Branch 87 → 88 taken 2001 times.
✗ Branch 87 → 89 not taken.
4231 armed ? " and armed it" : ", and its arm failed"
3322 );
3323
2/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✗ Branch 95 → 96 not taken.
✓ Branch 95 → 98 taken 2230 times.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✗ Branch 95 → 96 not taken.
✓ Branch 95 → 98 taken 2001 times.
4231 if (claimed)
3324 {
3325 ✗ note_position_claim(snapshot.name, target);
3326 }
3327 4231 DetourModKit::detail::emit_lifecycle_event(
3328 snapshot.name,
3329 snapshot.ledger_id,
3330 snapshot.kind,
3331 diagnostics::HookTransition::Created
3332 );
3333 4231 log_deferred_arm(deferred, snapshot.name, target);
3334
3/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 102 → 103 taken 2228 times.
✓ Branch 102 → 106 taken 2 times.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✓ Branch 102 → 103 taken 2001 times.
✗ Branch 102 → 106 not taken.
4231 if (deferred.transition)
3335 {
3336 4229 DetourModKit::detail::emit_lifecycle_event(
3337 snapshot.name,
3338 snapshot.ledger_id,
3339 snapshot.kind,
3340 4229 *deferred.transition
3341 );
3342 }
3343
3/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 107 → 108 taken 3 times.
✓ Branch 107 → 136 taken 2227 times.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✗ Branch 107 → 108 not taken.
✓ Branch 107 → 136 taken 2001 times.
4231 if (!armed)
3344 {
3345 // The teardown runs before the null store, so no thread that enters the detour reads a null original.
3346 // A pinned backend keeps its detour reachable and its trampoline valid, so its original stays.
3347 3 const auto failed = std::ranges::find_if(
3348 hooks,
3349 3 [&stored](const std::unique_ptr<Hook> &hook) noexcept { return hook.get() == &stored; }
3350 );
3351 3 bool pinned = false;
3352
1/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 116 → 117 taken 3 times.
✗ Branch 116 → 130 not taken.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✗ Branch 116 → 117 not taken.
✗ Branch 116 → 130 not taken.
6 if (failed != hooks.end())
3353 {
3354 6 std::unique_ptr<Hook> destroyed = std::move(*failed);
3355 3 hooks.erase(failed);
3356 3 pinned = teardown(*destroyed, CountedDrainProof::InstallRollback) == TeardownOutcome::Pinned;
3357 3 }
3358
1/4
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::InlineHook, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::(anonymous namespace)::install_inline_into_stack(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, DetourModKit::hook::InlineInstallRequest, void*, std::optional<DetourModKit::hook::detail::CountedInstall>)::{lambda(auto:1&)#1}&&):
✓ Branch 130 → 131 taken 3 times.
✗ Branch 130 → 132 not taken.
std::expected<std::reference_wrapper<DetourModKit::hook::Hook>, DetourModKit::Error> DetourModKit::hook::detail::HookAccess::install_into_stack<safetyhook::MidHook, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}>(std::vector<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> >, std::allocator<std::unique_ptr<DetourModKit::hook::Hook, std::default_delete<DetourModKit::hook::Hook> > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, DetourModKit::hook::detail::ReservedTarget const&, DetourModKit::hook::Options const&, DetourModKit::hook::OriginalSlot const&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}&&, DetourModKit::hook::HookStack::install(DetourModKit::hook::MidRequest, void (*)(DetourModKit::hook::MidContext&))::{lambda(auto:1&)#1}&&):
✗ Branch 130 → 131 not taken.
✗ Branch 130 → 132 not taken.
3 if (!pinned)
3359 {
3360 3 publish_original(original, nullptr);
3361 }
3362 3 return std::unexpected(armed.error());
3363 }
3364 4228 return std::ref(stored);
3365 4234 }
3366
3367 namespace
3368 {
3369 /// Runs HookStack::install for an inline hook. @p counted_install names the thunk of the counted form.
3370 2234 [[nodiscard]] Result<std::reference_wrapper<Hook>> install_inline_into_stack(
3371 std::vector<std::unique_ptr<Hook>> &hooks,
3372 InlineInstallRequest request,
3373 void *detour,
3374 std::optional<detail::CountedInstall> counted_install
3375 )
3376 {
3377
2/4
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 2235 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 2235 times.
6703 InlineRequest create_request{std::move(request.name), std::move(request.target), request.options};
3378 const Result<detail::ReservedTarget> preflight =
3379
2/2
✓ Branch 13 → 14 taken 2232 times.
✓ Branch 13 → 16 taken 3 times.
2235 preflight_inline_request(create_request, counted_install ? counted_install->entry : detour);
3380
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 24 taken 2234 times.
2235 if (!preflight)
3381 {
3382 1 return std::unexpected(preflight.error());
3383 }
3384 2234 std::optional<CountedThunk> counted;
3385 2234 void *destination = detour;
3386
2/2
✓ Branch 25 → 26 taken 2231 times.
✓ Branch 25 → 40 taken 3 times.
2234 if (counted_install)
3387 {
3388 Result<CountedThunk> thunk =
3389 2231 inspect_counted_install(create_request.name, *counted_install, *preflight);
3390
1/2
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 36 taken 2231 times.
2231 if (!thunk)
3391 {
3392 ✗ return std::unexpected(thunk.error());
3393 }
3394 2231 destination = thunk->range.begin;
3395 2231 counted = *thunk;
3396 }
3397 2234 const Result<HMODULE> module = acquire_install_module_ref(*preflight, "hook::inline_at");
3398
2/2
✓ Branch 43 → 44 taken 1 time.
✓ Branch 43 → 48 taken 2233 times.
2234 if (!module)
3399 {
3400 1 return std::unexpected(module.error());
3401 }
3402 2233 ModuleRefGuard self_ref(*module);
3403 2233 const std::uintptr_t target = preflight->address;
3404 4466 return detail::HookAccess::install_into_stack<safetyhook::InlineHook>(
3405 hooks,
3406 2233 std::move(create_request.name),
3407 *preflight,
3408 create_request.options,
3409 2233 request.original,
3410 6697 [target, destination](std::string_view name)
3411 2231 { return create_inline_backend(target, destination, name); },
3412 2233 [&self_ref, &counted](auto &impl) noexcept
3413 {
3414 2230 impl.counted = counted;
3415 2230 impl.self_ref = self_ref.release();
3416 2230 }
3417 2233 );
3418 2235 }
3419 } // namespace
3420
3421 3 Result<std::reference_wrapper<Hook>> HookStack::install_raw(InlineInstallRequest request, void *detour)
3422 {
3423 6 return install_inline_into_stack(m_hooks, std::move(request), detour, std::nullopt);
3424 }
3425
3426 Result<std::reference_wrapper<Hook>>
3427 2232 HookStack::install_counted(InlineInstallRequest request, detail::CountedInstall install)
3428 {
3429 4463 return install_inline_into_stack(m_hooks, std::move(request), nullptr, install);
3430 }
3431
3432 2001 Result<std::reference_wrapper<Hook>> HookStack::install(MidRequest request, MidHookFn detour)
3433 {
3434 2001 const Result<detail::ReservedTarget> preflight = preflight_mid_request(request, detour);
3435
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 9 taken 2001 times.
2001 if (!preflight)
3436 {
3437 ✗ return std::unexpected(preflight.error());
3438 }
3439 2001 const std::uintptr_t target = preflight->address;
3440 2001 const Result<HMODULE> module = acquire_install_module_ref(*preflight, "hook::mid_at");
3441
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 18 taken 2001 times.
2001 if (!module)
3442 {
3443 ✗ return std::unexpected(module.error());
3444 }
3445 2001 ModuleRefGuard self_ref(*module);
3446 2001 const Result<std::size_t> claim = claim_mid_adapter_for_install(target, preflight->ledger_id, detour);
3447
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 28 taken 2001 times.
2001 if (!claim)
3448 {
3449 ✗ return std::unexpected(claim.error());
3450 }
3451 2001 const std::size_t slot_index = *claim;
3452 2001 MidAdapterSlotGuard slot_guard(slot_index);
3453 2001 return detail::HookAccess::install_into_stack<safetyhook::MidHook>(
3454 2001 m_hooks,
3455 4002 std::move(request.name),
3456 *preflight,
3457 2001 request.options,
3458 4002 OriginalSlot{},
3459 2001 [target, slot_index](std::string_view name) { return create_mid_backend(target, slot_index, name); },
3460 2001 [&self_ref, &slot_guard](auto &impl) noexcept
3461 {
3462 2001 impl.self_ref = self_ref.release();
3463 2001 impl.mid_slot = slot_guard.release();
3464 2001 }
3465 2001 );
3466 2001 }
3467
3468 9 Result<std::vector<InstallOutcome>> install_all(std::span<const HookSpec> table) noexcept
3469 {
3470
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 9 taken 8 times.
9 if (std::optional<Error> vetoed = refuse_on_loader_lock("hook::install_all"))
3471 {
3472 1 return std::unexpected(*vetoed);
3473 }
3474 #if defined(DMK_ENABLE_TEST_SEAMS)
3475 8 note_loader_veto_passed(DetourModKit::detail::HookLoaderEntry::InstallAll);
3476 #endif
3477 // InstallRollback removes a partial install newest-first, so every layered row restores. A vector's
3478 // front-to-back destruction leaves lower rows as residue. InstallRollback handles mandatory misses and
3479 // exceptions unless commit() moves the rows out.
3480 class InstallRollback
3481 {
3482 public:
3483 InstallRollback() = default;
3484 InstallRollback(const InstallRollback &) = delete;
3485 InstallRollback &operator=(const InstallRollback &) = delete;
3486 8 ~InstallRollback()
3487 {
3488
2/2
✓ Branch 5 → 3 taken 3 times.
✓ Branch 5 → 6 taken 8 times.
11 while (!m_rows.empty())
3489 {
3490 3 m_rows.pop_back();
3491 }
3492 8 }
3493
3494 17 [[nodiscard]] std::vector<InstallOutcome> &rows() noexcept { return m_rows; }
3495 10 [[nodiscard]] std::vector<InstallOutcome> commit() noexcept { return std::move(m_rows); }
3496
3497 private:
3498 std::vector<InstallOutcome> m_rows;
3499 };
3500
3501 try
3502 {
3503 8 InstallRollback rollback;
3504
2/2
✓ Branch 12 → 13 taken 7 times.
✓ Branch 12 → 139 taken 1 time.
8 rollback.rows().reserve(table.size());
3505
2/2
✓ Branch 90 → 15 taken 11 times.
✓ Branch 90 → 91 taken 5 times.
23 for (const HookSpec &spec : table)
3506 {
3507 // The OwnedScanRequest copy preserves the caller table entries for install_all. Each row's Options
3508 // value carries its install policy.
3509
1/2
✓ Branch 17 → 18 taken 11 times.
✗ Branch 17 → 137 not taken.
11 Target target = spec.m_target;
3510 11 Result<Hook> installed = std::holds_alternative<InlineDetour>(spec.m_detour)
3511 11 ? detail::inline_at_raw(
3512
5/20
✓ Branch 40 → 41 taken 11 times.
✗ Branch 40 → 42 not taken.
✓ Branch 42 → 43 taken 11 times.
✗ Branch 42 → 45 not taken.
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 45 taken 11 times.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 11 times.
✓ Branch 48 → 49 taken 11 times.
✗ Branch 48 → 50 not taken.
✗ Branch 110 → 111 not taken.
✗ Branch 110 → 112 not taken.
✗ Branch 114 → 115 not taken.
✗ Branch 114 → 117 not taken.
✗ Branch 115 → 116 not taken.
✗ Branch 115 → 117 not taken.
✗ Branch 118 → 119 not taken.
✗ Branch 118 → 120 not taken.
✗ Branch 121 → 122 not taken.
✗ Branch 121 → 123 not taken.
44 InlineRequest{spec.m_name, std::move(target), spec.m_options},
3513
2/4
✓ Branch 20 → 21 taken 11 times.
✗ Branch 20 → 98 not taken.
✓ Branch 21 → 22 taken 11 times.
✗ Branch 21 → 98 not taken.
11 std::get<InlineDetour>(spec.m_detour).fn
3514 )
3515 : mid_at(
3516
3/20
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 34 taken 11 times.
✗ Branch 34 → 35 not taken.
✓ Branch 34 → 37 taken 11 times.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 40 taken 11 times.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
✗ Branch 98 → 99 not taken.
✗ Branch 98 → 100 not taken.
✗ Branch 102 → 103 not taken.
✗ Branch 102 → 105 not taken.
✗ Branch 103 → 104 not taken.
✗ Branch 103 → 105 not taken.
✗ Branch 106 → 107 not taken.
✗ Branch 106 → 109 not taken.
✗ Branch 107 → 108 not taken.
✗ Branch 107 → 109 not taken.
11 MidRequest{spec.m_name, std::move(target), spec.m_options},
3517
0/2
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 98 not taken.
✗ std::get<MidHookFn>(spec.m_detour)
3518
2/8
✓ Branch 19 → 20 taken 11 times.
✗ Branch 19 → 26 not taken.
✓ Branch 25 → 32 taken 11 times.
✗ Branch 25 → 98 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 98 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 98 not taken.
22 );
3519
3520
6/6
✓ Branch 54 → 55 taken 4 times.
✓ Branch 54 → 57 taken 7 times.
✓ Branch 55 → 56 taken 2 times.
✓ Branch 55 → 57 taken 2 times.
✓ Branch 58 → 59 taken 2 times.
✓ Branch 58 → 63 taken 9 times.
11 if (!installed && spec.m_severity == Severity::Mandatory)
3521 {
3522 // Fail fast: ~InstallRollback unhooks every already-installed row newest-first before the
3523 // error propagates.
3524 2 return std::unexpected(installed.error());
3525 }
3526
3/8
✓ Branch 64 → 65 taken 9 times.
✗ Branch 64 → 132 not taken.
✓ Branch 68 → 69 taken 9 times.
✗ Branch 68 → 127 not taken.
✗ Branch 70 → 71 not taken.
✓ Branch 70 → 72 taken 9 times.
✗ Branch 129 → 130 not taken.
✗ Branch 129 → 131 not taken.
18 rollback.rows().push_back(InstallOutcome{spec.m_name, spec.m_severity, std::move(installed)});
3527
4/4
✓ Branch 74 → 75 taken 9 times.
✓ Branch 74 → 76 taken 2 times.
✓ Branch 78 → 79 taken 9 times.
✓ Branch 78 → 83 taken 2 times.
13 }
3528 5 return rollback.commit();
3529 8 }
3530
1/2
✓ Branch 142 → 143 taken 1 time.
✗ Branch 142 → 147 not taken.
1 catch (const std::bad_alloc &)
3531 {
3532 1 return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::install_all"});
3533 1 }
3534 ✗ catch (...)
3535 {
3536 ✗ return std::unexpected(Error{ErrorCode::UnknownError, "hook::install_all"});
3537 ✗ }
3538 }
3539
3540 206 bool is_target_hooked(Address target) noexcept
3541 {
3542 206 return DetourModKit::detail::HookLedger::instance().is_target_hooked(target.raw());
3543 }
3544
3545 // VmtHook is the RAII handle for a cloned vtable and its object-level clone lifecycle.
3546 212 VmtHook::VmtHook(std::unique_ptr<Impl> impl) noexcept : m_impl(std::move(impl)) {}
3547
3548 432 VmtHook::VmtHook(VmtHook &&other) noexcept : m_impl(std::move(other.m_impl)) {}
3549
3550 ✗ VmtHook &VmtHook::operator=(VmtHook &&other) noexcept
3551 {
3552
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 11 not taken.
✗ if (this != &other)
3553 {
3554 ✗ VmtHook discard(std::move(*this));
3555 ✗ m_impl = std::move(other.m_impl);
3556 ✗ }
3557 ✗ return *this;
3558 }
3559
3560 420 VmtHook::~VmtHook() noexcept
3561 {
3562
2/2
✓ Branch 3 → 4 taken 218 times.
✓ Branch 3 → 5 taken 103 times.
321 if (!m_impl)
3563 {
3564 222 return;
3565 }
3566 // Loader-lock leaf discipline requires an Impl leak instead of vptr restoration here. Its module reference
3567 // keeps the clone code pages mapped.
3568
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 10 taken 103 times.
103 if (!DetourModKit::detail::blocking_teardown_permitted())
3569 {
3570 ✗ diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
3571 ✗ (void)m_impl.release();
3572 ✗ return;
3573 }
3574 103 const std::uint64_t ledger_id = m_impl->ledger_id;
3575 // Copy the name out before reset destroys its storage. Contain an OOM exception and degrade to an empty
3576 // name (noexcept destructor).
3577 103 std::string name;
3578 try
3579 {
3580
1/2
✓ Branch 13 → 14 taken 103 times.
✗ Branch 13 → 86 not taken.
103 name = m_impl->name;
3581 }
3582 ✗ catch (...)
3583 {
3584 ✗ }
3585 // Teardown restores every applied object before it releases the ledger entry per Hook::~Hook order. This
3586 // order prevents a race between a vmt_for or apply_to operation and clone removal.
3587 103 HMODULE self_ref = nullptr;
3588 {
3589 103 std::unique_lock<std::mutex> object_gate = acquire_vmt_object_lock();
3590
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 20 taken 103 times.
103 if (!object_gate.owns_lock())
3591 {
3592 // Leak the Impl rather than restore vptrs without the gate.
3593 ✗ diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
3594 ✗ (void)m_impl.release();
3595 ✗ return;
3596 }
3597 // Restore every object with known state. A different vptr can belong to a successor that recorded this
3598 // clone as its original. An unreadable or non-writable word is equally unsafe to overwrite.
3599 103 std::size_t unrestorable = 0;
3600
2/2
✓ Branch 50 → 23 taken 102 times.
✓ Branch 50 → 51 taken 103 times.
308 for (const auto &binding : m_impl->object_bindings)
3601 {
3602 102 const DetourModKit::detail::ObjectWordResult word = DetourModKit::detail::validate_vmt_object_word(
3603 102 reinterpret_cast<std::uintptr_t>(binding.object)
3604 );
3605
1/2
✓ Branch 26 → 27 taken 102 times.
✗ Branch 26 → 29 not taken.
102 if (word.verdict != DetourModKit::detail::ObjectWordVerdict::Unreadable &&
3606
2/2
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 29 taken 101 times.
102 word.vptr == binding.original_vptr)
3607 {
3608 98 continue;
3609 }
3610
3/4
✓ Branch 29 → 30 taken 101 times.
✗ Branch 29 → 33 not taken.
✓ Branch 34 → 35 taken 97 times.
✓ Branch 34 → 39 taken 4 times.
202 if (word.verdict == DetourModKit::detail::ObjectWordVerdict::Ok &&
3611
2/2
✓ Branch 31 → 32 taken 97 times.
✓ Branch 31 → 33 taken 4 times.
101 word.vptr == m_impl->cloned_vptr_base)
3612 {
3613
1/2
✓ Branch 37 → 38 taken 97 times.
✗ Branch 37 → 39 not taken.
97 if (publish_vmt_object_word(binding.object, m_impl->cloned_vptr_base, binding.original_vptr))
3614 {
3615 97 continue;
3616 }
3617 }
3618 4 ++unrestorable;
3619 }
3620
2/2
✓ Branch 51 → 52 taken 4 times.
✓ Branch 51 → 63 taken 99 times.
103 if (unrestorable > 0)
3621 {
3622 4 const std::size_t object_count = m_impl->object_bindings.size();
3623 4 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
3624 4 (void)m_impl.release();
3625 4 object_gate.unlock();
3626 #if defined(DMK_ENABLE_TEST_SEAMS)
3627
2/2
✓ Branch 57 → 58 taken 1 time.
✓ Branch 57 → 59 taken 3 times.
4 if (auto *probe = DetourModKit::detail::g_vmt_teardown_warning_probe)
3628 {
3629 1 probe();
3630 }
3631 #endif
3632 8 (void)log().try_log(
3633 LogLevel::Warning,
3634 "hook::~VmtHook: VMT hook '{}' destroyed while {} of its {} object(s) could "
3635 "not be provably restored to their original vtable; leaked this clone to "
3636 "avoid a vtable use-after-free. Destroy VMT hooks newest-first to restore "
3637 "the original table.",
3638 4 std::string_view{name},
3639 unrestorable,
3640 object_count
3641 );
3642 4 return;
3643 }
3644 99 self_ref = static_cast<HMODULE>(m_impl->self_ref);
3645 99 m_impl.reset();
3646
2/2
✓ Branch 67 → 68 taken 99 times.
✓ Branch 67 → 75 taken 4 times.
103 }
3647 // Release outside the object gate: FreeLibrary takes the loader lock, which must not nest inside the
3648 // process-wide VMT gate.
3649 99 DetourModKit::detail::release_module_ref(self_ref, diagnostics::ModulePinReason::Hook);
3650 99 DetourModKit::detail::HookLedger::instance().release_vmt(ledger_id);
3651 // A VMT hook is live from creation and has no enable/disable transition, so it is always counted armed.
3652 99 emit_lifecycle(
3653 name,
3654 ledger_id,
3655 diagnostics::HookKind::Vmt,
3656 diagnostics::HookTransition::Removed,
3657 RemovalPopulationState{
3658 .was_active = true,
3659 }
3660 );
3661
4/4
✓ Branch 77 → 78 taken 99 times.
✓ Branch 77 → 80 taken 4 times.
✓ Branch 82 → 83 taken 99 times.
✓ Branch 82 → 84 taken 222 times.
424 }
3662
3663 8 VmtHook::operator bool() const noexcept
3664 {
3665 8 return m_impl != nullptr;
3666 }
3667
3668 2 std::string_view VmtHook::name() const noexcept
3669 {
3670
1/2
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 6 not taken.
2 return m_impl ? std::string_view{m_impl->name} : std::string_view{};
3671 }
3672
3673 41 Result<void> VmtHook::apply_to(void *object, VmtOptions options)
3674 {
3675
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 9 taken 40 times.
41 if (std::optional<Error> vetoed = refuse_on_loader_lock("hook::vmt_apply"))
3676 {
3677 1 return std::unexpected(*vetoed);
3678 }
3679 #if defined(DMK_ENABLE_TEST_SEAMS)
3680 40 note_loader_veto_passed(DetourModKit::detail::HookLoaderEntry::VmtApply);
3681 #endif
3682
2/2
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 15 taken 39 times.
40 if (!m_impl)
3683 {
3684 1 return std::unexpected(Error{ErrorCode::InvalidHookState, "hook::vmt_apply"});
3685 }
3686
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 19 taken 38 times.
39 if (object == nullptr)
3687 {
3688 1 return std::unexpected(Error{ErrorCode::InvalidObject, "hook::vmt_apply"});
3689 }
3690 38 std::unique_lock<std::mutex> object_gate = acquire_vmt_object_lock();
3691
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 25 taken 38 times.
38 if (!object_gate.owns_lock())
3692 {
3693 ✗ return std::unexpected(Error{ErrorCode::UnknownError, "hook::vmt_apply"});
3694 }
3695 // Exclusive write keeps the policy decision and guarded swap atomic against this handle's readers. The
3696 // process-wide object gate serializes the vptr transition against other DMK VMT handles.
3697
1/2
✓ Branch 26 → 27 taken 38 times.
✗ Branch 26 → 100 not taken.
38 std::unique_lock<DetourModKit::detail::SrwSharedMutex> gate(m_impl->method_mutex);
3698 // Object-word validation is not a policy: every option set requires a capturable writable word, and the
3699 // later guarded compare-exchange closes a protection/unmap race.
3700 const DetourModKit::detail::ObjectWordResult word =
3701 38 DetourModKit::detail::validate_vmt_object_word(reinterpret_cast<std::uintptr_t>(object));
3702
2/2
✓ Branch 28 → 29 taken 18 times.
✓ Branch 28 → 32 taken 20 times.
38 if (word.verdict != DetourModKit::detail::ObjectWordVerdict::Ok)
3703 {
3704 18 return std::unexpected(Error{ErrorCode::InvalidObject, "hook::vmt_apply", word.detail});
3705 }
3706 20 const std::uintptr_t current_vptr = word.vptr;
3707 // Locate this object's restoration binding before any policy branch. Teardown restores from the
3708 // binding. Refusal is the only outcome that keeps every recorded original true.
3709
1/2
✓ Branch 36 → 37 taken 20 times.
✗ Branch 36 → 98 not taken.
40 const auto binding = std::find_if(
3710 20 m_impl->object_bindings.begin(),
3711 20 m_impl->object_bindings.end(),
3712 20 [object](const auto &entry) -> bool { return entry.object == object; }
3713 );
3714 20 const bool already_tracked = binding != m_impl->object_bindings.end();
3715
2/2
✓ Branch 46 → 47 taken 3 times.
✓ Branch 46 → 52 taken 17 times.
20 if (current_vptr == m_impl->cloned_vptr_base)
3716 {
3717
2/2
✓ Branch 47 → 48 taken 2 times.
✓ Branch 47 → 51 taken 1 time.
3 if (!already_tracked)
3718 {
3719 // This handle holds no original vptr for this object. A new binding records the clone base as its
3720 // own original, and teardown then frees the clone below it.
3721 2 return std::unexpected(Error{ErrorCode::HookAlreadyExists, "hook::vmt_apply", current_vptr});
3722 }
3723 // If the object already uses this handle's clone, every policy treats the apply as a no-op.
3724 1 return {};
3725 }
3726
5/6
✓ Branch 52 → 53 taken 1 time.
✓ Branch 52 → 57 taken 16 times.
✓ Branch 55 → 56 taken 1 time.
✗ Branch 55 → 57 not taken.
✓ Branch 58 → 59 taken 1 time.
✓ Branch 58 → 62 taken 16 times.
18 else if (already_tracked && current_vptr != binding->original_vptr)
3727 {
3728 // Another actor moved the object off the recorded vptr, usually through a newer layer. A new
3729 // publication displaces state that this binding does not name.
3730 1 return std::unexpected(Error{ErrorCode::HookAlreadyExists, "hook::vmt_apply", current_vptr});
3731 }
3732
2/2
✓ Branch 66 → 67 taken 2 times.
✓ Branch 66 → 71 taken 14 times.
16 if (const std::optional<Error> refused =
3733 16 check_vmt_apply_options(options, current_vptr, m_impl->name, object))
3734 {
3735 2 return std::unexpected(*refused);
3736 }
3737 // Reserve the restoration binding before publication. Capacity growth after publication can throw with
3738 // the object already on the clone but absent from the state that teardown needs.
3739
1/2
✓ Branch 71 → 72 taken 14 times.
✗ Branch 71 → 76 not taken.
14 if (!already_tracked)
3740 {
3741 try
3742 {
3743
2/2
✓ Branch 75 → 76 taken 12 times.
✓ Branch 75 → 91 taken 2 times.
14 m_impl->object_bindings.reserve(m_impl->object_bindings.size() + 1);
3744 }
3745
1/2
✗ Branch 91 → 92 not taken.
✓ Branch 91 → 93 taken 2 times.
2 catch (const std::bad_alloc &)
3746 {
3747 2 return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::vmt_apply"});
3748 2 }
3749 }
3750
2/2
✓ Branch 78 → 79 taken 4 times.
✓ Branch 78 → 82 taken 8 times.
12 if (!publish_vmt_object_word(object, current_vptr, m_impl->cloned_vptr_base))
3751 {
3752 4 return std::unexpected(
3753 4 Error{ErrorCode::InvalidObject, "hook::vmt_apply", reinterpret_cast<std::uintptr_t>(object)}
3754 4 );
3755 }
3756
1/2
✓ Branch 82 → 83 taken 8 times.
✗ Branch 82 → 86 not taken.
8 if (!already_tracked)
3757 {
3758 // The reserved capacity guarantees that this push cannot throw.
3759
1/2
✓ Branch 84 → 85 taken 8 times.
✗ Branch 84 → 97 not taken.
8 m_impl->object_bindings.push_back({object, current_vptr});
3760 }
3761 8 return {};
3762 38 }
3763
3764 14 Result<void> VmtHook::remove_from(void *object)
3765 {
3766
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 9 taken 13 times.
14 if (std::optional<Error> vetoed = refuse_on_loader_lock("hook::vmt_remove"))
3767 {
3768 1 return std::unexpected(*vetoed);
3769 }
3770 #if defined(DMK_ENABLE_TEST_SEAMS)
3771 13 note_loader_veto_passed(DetourModKit::detail::HookLoaderEntry::VmtRemove);
3772 #endif
3773
2/2
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 15 taken 12 times.
13 if (!m_impl)
3774 {
3775 1 return std::unexpected(Error{ErrorCode::InvalidHookState, "hook::vmt_remove"});
3776 }
3777
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 19 taken 11 times.
12 if (object == nullptr)
3778 {
3779 1 return std::unexpected(Error{ErrorCode::InvalidObject, "hook::vmt_remove"});
3780 }
3781 11 std::unique_lock<std::mutex> object_gate = acquire_vmt_object_lock();
3782
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 25 taken 11 times.
11 if (!object_gate.owns_lock())
3783 {
3784 ✗ return std::unexpected(Error{ErrorCode::UnknownError, "hook::vmt_remove"});
3785 }
3786 // The exclusive write prevents a race between unapply and an original() snapshot reader during transition.
3787
1/2
✓ Branch 26 → 27 taken 11 times.
✗ Branch 26 → 77 not taken.
11 std::unique_lock<DetourModKit::detail::SrwSharedMutex> gate(m_impl->method_mutex);
3788
1/2
✓ Branch 31 → 32 taken 11 times.
✗ Branch 31 → 75 not taken.
22 const auto binding = std::find_if(
3789 11 m_impl->object_bindings.begin(),
3790 11 m_impl->object_bindings.end(),
3791 18 [object](const auto &entry) -> bool { return entry.object == object; }
3792 );
3793
1/2
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 11 times.
22 if (binding == m_impl->object_bindings.end())
3794 {
3795 ✗ return {};
3796 }
3797
3798 // Keep the full binding if a successor still outranks this clone. A later rollback can return it here.
3799 const DetourModKit::detail::ObjectWordResult word =
3800 11 DetourModKit::detail::validate_vmt_object_word(reinterpret_cast<std::uintptr_t>(object));
3801
5/6
✓ Branch 43 → 44 taken 11 times.
✗ Branch 43 → 47 not taken.
✓ Branch 45 → 46 taken 9 times.
✓ Branch 45 → 47 taken 2 times.
✓ Branch 48 → 49 taken 9 times.
✓ Branch 48 → 53 taken 2 times.
11 if (word.verdict == DetourModKit::detail::ObjectWordVerdict::Ok && word.vptr == m_impl->cloned_vptr_base)
3802 {
3803 // The re-read below is the authority: an object already at its original restores nothing yet must
3804 // still release its binding.
3805 9 (void)publish_vmt_object_word(object, m_impl->cloned_vptr_base, binding->original_vptr);
3806 }
3807
3808 const std::optional<std::uintptr_t> after =
3809 11 DetourModKit::detail::guarded_read<std::uintptr_t>(reinterpret_cast<std::uintptr_t>(object));
3810
5/6
✓ Branch 55 → 56 taken 11 times.
✗ Branch 55 → 61 not taken.
✓ Branch 59 → 60 taken 9 times.
✓ Branch 59 → 61 taken 2 times.
✓ Branch 62 → 63 taken 9 times.
✓ Branch 62 → 69 taken 2 times.
22 if (after && *after == binding->original_vptr)
3811 {
3812
1/2
✓ Branch 67 → 68 taken 9 times.
✗ Branch 67 → 74 not taken.
18 m_impl->object_bindings.erase(binding);
3813 }
3814 11 return {};
3815 11 }
3816
3817 244 Result<void> VmtHook::hook_method_raw(std::size_t index, void *detour)
3818 {
3819
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 9 taken 243 times.
244 if (std::optional<Error> vetoed = refuse_on_loader_lock("hook::vmt_hook_method"))
3820 {
3821 1 return std::unexpected(*vetoed);
3822 }
3823 #if defined(DMK_ENABLE_TEST_SEAMS)
3824 243 note_loader_veto_passed(DetourModKit::detail::HookLoaderEntry::VmtHookMethod);
3825 #endif
3826
2/2
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 15 taken 241 times.
243 if (!m_impl)
3827 {
3828 2 return std::unexpected(Error{ErrorCode::InvalidHookState, "hook::vmt_hook_method"});
3829 }
3830
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 19 taken 240 times.
241 if (detour == nullptr)
3831 {
3832 1 return std::unexpected(Error{ErrorCode::InvalidArg, "hook::vmt_hook_method"});
3833 }
3834 {
3835 // The map insert and backend slot patch must be atomic against a concurrent original() snapshot reader.
3836 // That reader traverses this same map under the shared read.
3837
1/2
✓ Branch 20 → 21 taken 240 times.
✗ Branch 20 → 102 not taken.
240 std::unique_lock<DetourModKit::detail::SrwSharedMutex> gate(m_impl->method_mutex);
3838
2/2
✓ Branch 22 → 23 taken 4 times.
✓ Branch 22 → 26 taken 236 times.
240 if (index >= m_impl->method_count)
3839 {
3840 4 return std::unexpected(Error{ErrorCode::InvalidArg, "hook::vmt_hook_method", index});
3841 }
3842
3/4
✓ Branch 27 → 28 taken 236 times.
✗ Branch 27 → 100 not taken.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 32 taken 235 times.
236 if (m_impl->method_hooks.contains(index))
3843 {
3844 // One method hook exists per slot. A second hook reads the first detour as the "original" and
3845 // creates a silent mod chain.
3846 1 return std::unexpected(Error{ErrorCode::MethodAlreadyHooked, "hook::vmt_hook_method", index});
3847 }
3848 235 auto node = m_impl->method_hooks.end();
3849 try
3850 {
3851 // Allocate the map node before the backend stores the slot. No allocation can then fail over a
3852 // live slot, and original() resolves from the instant a detour can run. The original comes from
3853 // the clone, whose slot index matches the method index.
3854
2/2
✓ Branch 35 → 36 taken 35 times.
✓ Branch 35 → 69 taken 200 times.
235 node = m_impl->method_hooks.try_emplace(index).first;
3855 35 node->second.original = reinterpret_cast<void *const *>(m_impl->cloned_vptr_base)[index];
3856 // A void* detour installs the same 8 bytes as a typed pointer. hook_method<Fn> vetted the ABI.
3857
1/2
✓ Branch 39 → 40 taken 35 times.
✗ Branch 39 → 72 not taken.
35 auto created = m_impl->backend.hook_method(index, detour);
3858
1/2
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 47 taken 35 times.
35 if (!created)
3859 {
3860
0/2
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 70 not taken.
✗ m_impl->method_hooks.erase(node);
3861 ✗ return std::unexpected(Error{ErrorCode::BackendFailed, "hook::vmt_hook_method", index});
3862 }
3863
1/2
✓ Branch 47 → 48 taken 35 times.
✗ Branch 47 → 70 not taken.
70 node->second.backend = std::move(created.value());
3864
1/2
✓ Branch 54 → 55 taken 35 times.
✗ Branch 54 → 57 not taken.
35 }
3865
1/2
✓ Branch 73 → 74 taken 200 times.
✗ Branch 73 → 85 not taken.
200 catch (const std::bad_alloc &)
3866 {
3867
1/2
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 81 taken 200 times.
200 if (node != m_impl->method_hooks.end())
3868 {
3869
0/2
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 96 not taken.
✗ m_impl->method_hooks.erase(node);
3870 }
3871 200 return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::vmt_hook_method", index});
3872 200 }
3873 ✗ catch (...)
3874 {
3875
0/2
✗ Branch 89 → 90 not taken.
✗ Branch 89 → 92 not taken.
✗ if (node != m_impl->method_hooks.end())
3876 {
3877
0/2
✗ Branch 91 → 92 not taken.
✗ Branch 91 → 98 not taken.
✗ m_impl->method_hooks.erase(node);
3878 }
3879 ✗ return std::unexpected(Error{ErrorCode::BackendFailed, "hook::vmt_hook_method", index});
3880
0/2
✗ Branch 94 → 95 not taken.
✗ Branch 94 → 100 not taken.
✗ }
3881
2/2
✓ Branch 59 → 60 taken 35 times.
✓ Branch 59 → 65 taken 205 times.
240 }
3882 // This post-commit best-effort log contains a format bad_alloc, so it cannot flip a committed install into
3883 // a failure.
3884 try
3885 {
3886
1/2
✓ Branch 64 → 66 taken 35 times.
✗ Branch 64 → 103 not taken.
70 log().info(
3887 "hook::hook_method: hooked method index {} on VMT hook '{}'.",
3888 index,
3889 70 std::string_view{m_impl->name}
3890 );
3891 }
3892 ✗ catch (...)
3893 {
3894 ✗ }
3895 35 return {};
3896 }
3897
3898 241 void *VmtHook::method_original_address(std::size_t index) const noexcept
3899 {
3900
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 240 times.
241 if (!m_impl)
3901 {
3902 1 return nullptr;
3903 }
3904 // A shared read serializes the snapshot against exclusive writers. The copied pointer is then called
3905 // lock-free by contract (see original()).
3906 240 std::shared_lock<DetourModKit::detail::SrwSharedMutex> gate(m_impl->method_mutex);
3907 240 const auto it = m_impl->method_hooks.find(index);
3908
2/2
✓ Branch 12 → 13 taken 157 times.
✓ Branch 12 → 14 taken 83 times.
240 if (it == m_impl->method_hooks.end())
3909 {
3910 157 return nullptr;
3911 }
3912 83 return it->second.original;
3913 240 }
3914
3915 7 Result<void> VmtHook::remove_method(std::size_t index)
3916 {
3917
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 9 taken 6 times.
7 if (std::optional<Error> vetoed = refuse_on_loader_lock("hook::vmt_remove_method"))
3918 {
3919 1 return std::unexpected(*vetoed);
3920 }
3921 #if defined(DMK_ENABLE_TEST_SEAMS)
3922 6 note_loader_veto_passed(DetourModKit::detail::HookLoaderEntry::VmtRemoveMethod);
3923 #endif
3924
2/2
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 15 taken 4 times.
6 if (!m_impl)
3925 {
3926 2 return std::unexpected(Error{ErrorCode::InvalidHookState, "hook::vmt_remove_method"});
3927 }
3928 {
3929 // An exclusive write runs the VmHook destructor when it erases the entry. The destructor restores the
3930 // cloned slot to its original pointer. That restore must not race an original() snapshot reader.
3931
1/2
✓ Branch 16 → 17 taken 4 times.
✗ Branch 16 → 42 not taken.
4 std::unique_lock<DetourModKit::detail::SrwSharedMutex> gate(m_impl->method_mutex);
3932
1/2
✓ Branch 18 → 19 taken 4 times.
✗ Branch 18 → 40 not taken.
4 const auto it = m_impl->method_hooks.find(index);
3933
2/2
✓ Branch 22 → 23 taken 1 time.
✓ Branch 22 → 26 taken 3 times.
4 if (it == m_impl->method_hooks.end())
3934 {
3935 1 return std::unexpected(Error{ErrorCode::MethodNotFound, "hook::vmt_remove_method", index});
3936 }
3937
1/2
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 40 not taken.
3 m_impl->method_hooks.erase(it);
3938
2/2
✓ Branch 30 → 31 taken 3 times.
✓ Branch 30 → 36 taken 1 time.
4 }
3939 // This post-commit log is best-effort. Contain a format bad_alloc.
3940 try
3941 {
3942
1/2
✓ Branch 35 → 37 taken 3 times.
✗ Branch 35 → 43 not taken.
6 log().info(
3943 "hook::remove_method: removed method index {} from VMT hook '{}'.",
3944 index,
3945 6 std::string_view{m_impl->name}
3946 );
3947 }
3948 ✗ catch (...)
3949 {
3950 ✗ }
3951 3 return {};
3952 }
3953
3954 2 void VmtHook::release() noexcept
3955 {
3956
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
2 if (!m_impl)
3957 {
3958 ✗ return;
3959 }
3960 // Leak the cloned vtable intentionally. Applied objects keep the clone for the process lifetime. The ledger
3961 // entry stays so is_vmt_clone_base still recognizes the live clone base. HookManager records the leak.
3962 2 diagnostics::record_intentional_leak(diagnostics::LeakSubsystem::HookManager);
3963 2 (void)m_impl.release();
3964 }
3965
3966 149 Result<VmtHook> vmt_for(std::string name, void *object, VmtOptions options)
3967 {
3968
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 9 taken 148 times.
149 if (std::optional<Error> vetoed = refuse_on_loader_lock("hook::vmt_for"))
3969 {
3970 1 return std::unexpected(*vetoed);
3971 }
3972 #if defined(DMK_ENABLE_TEST_SEAMS)
3973 148 note_loader_veto_passed(DetourModKit::detail::HookLoaderEntry::VmtFor);
3974 #endif
3975
2/2
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 15 taken 147 times.
148 if (name.empty())
3976 {
3977 1 return std::unexpected(Error{ErrorCode::InvalidArg, "hook::vmt_for"});
3978 }
3979
2/2
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 19 taken 145 times.
147 if (object == nullptr)
3980 {
3981 2 return std::unexpected(Error{ErrorCode::InvalidObject, "hook::vmt_for"});
3982 }
3983 // Take the module reference before the process-wide VMT object gate. A rollback runs FreeLibrary, which
3984 // takes the loader lock and must not nest inside the gate per ~VmtHook lock order. Declare the guard first.
3985 // The gate then unlocks first, so the guard FreeLibrary call always runs outside it.
3986 145 ModuleRefGuard self_ref(acquire_hook_self_ref());
3987
2/2
✓ Branch 22 → 23 taken 1 time.
✓ Branch 22 → 27 taken 144 times.
145 if (self_ref.get() == nullptr)
3988 {
3989 // acquire_module_ref restores GetLastError() on failure (error.hpp documents the detail contract).
3990
1/2
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 125 not taken.
1 return std::unexpected(Error{ErrorCode::SystemCallFailed, "hook::vmt_for", ::GetLastError()});
3991 }
3992 144 std::unique_lock<std::mutex> object_gate = acquire_vmt_object_lock();
3993
1/2
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 33 taken 144 times.
144 if (!object_gate.owns_lock())
3994 {
3995 ✗ return std::unexpected(Error{ErrorCode::UnknownError, "hook::vmt_for"});
3996 }
3997 // Object-word validation is not a policy (see apply_to).
3998 const DetourModKit::detail::ObjectWordResult word =
3999 144 DetourModKit::detail::validate_vmt_object_word(reinterpret_cast<std::uintptr_t>(object));
4000
2/2
✓ Branch 34 → 35 taken 17 times.
✓ Branch 34 → 38 taken 127 times.
144 if (word.verdict != DetourModKit::detail::ObjectWordVerdict::Ok)
4001 {
4002 17 return std::unexpected(Error{ErrorCode::InvalidObject, "hook::vmt_for", word.detail});
4003 }
4004 127 const std::uintptr_t current_vptr = word.vptr;
4005
2/2
✓ Branch 41 → 42 taken 5 times.
✓ Branch 41 → 46 taken 122 times.
127 if (const std::optional<Error> refused = check_vmt_for_options(options, current_vptr, name, object))
4006 {
4007 5 return std::unexpected(*refused);
4008 }
4009 // The slot walk and the clone classify method pages through VirtualQuery. The backend coordinator excludes
4010 // a trap window that holds such a page at PAGE_READWRITE, which ends the walk early and publishes a
4011 // truncated clone (`[B-66]`). HookBackendTrapWindow.VmtForWaitsForTheBackendTrapWindow pins the exclusion.
4012 DetourModKit::detail::BackendCoordinatorHold coordinator{
4013 122 DetourModKit::detail::WaitUntilHeld{"hook::vmt_for", name}
4014 244 };
4015
1/2
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 57 taken 122 times.
122 if (!coordinator)
4016 {
4017 ✗ log_vmt_coordinator_refusal(name, object, coordinator.refusal());
4018 ✗ return std::unexpected(Error{ErrorCode::BackendFailed, "hook::vmt_for", current_vptr});
4019 }
4020 122 const Result<std::size_t> slot_budget = count_vmt_clone_budget(current_vptr, object);
4021
2/2
✓ Branch 59 → 60 taken 2 times.
✓ Branch 59 → 64 taken 120 times.
122 if (!slot_budget)
4022 {
4023 2 return std::unexpected(slot_budget.error());
4024 }
4025 #if defined(DMK_ENABLE_TEST_SEAMS)
4026
2/2
✓ Branch 64 → 65 taken 3 times.
✓ Branch 64 → 66 taken 117 times.
120 if (auto *probe = DetourModKit::detail::g_vmt_before_capture_probe)
4027 {
4028 3 probe();
4029 }
4030 #endif
4031 try
4032 {
4033
2/2
✓ Branch 67 → 68 taken 113 times.
✓ Branch 67 → 133 taken 7 times.
120 Result<DetachedVmtBackend> cloned = clone_vmt_snapshot(current_vptr, *slot_budget);
4034 // The clone is complete, so release the coordinator before the ledger, the publication, and the
4035 // subscriber code below.
4036 113 coordinator.release();
4037
2/2
✓ Branch 70 → 71 taken 1 time.
✓ Branch 70 → 75 taken 112 times.
113 if (!cloned)
4038 {
4039 1 return std::unexpected(cloned.error());
4040 }
4041 112 const std::uintptr_t cloned_vptr_base = cloned->cloned_vptr_base;
4042 auto impl = std::make_unique<VmtHook::Impl>(
4043 112 std::move(cloned->backend),
4044 112 std::move(name),
4045 cloned_vptr_base,
4046 112 cloned->method_count,
4047 113 0
4048
2/2
✓ Branch 82 → 83 taken 111 times.
✓ Branch 82 → 127 taken 1 time.
112 );
4049
2/2
✓ Branch 84 → 85 taken 110 times.
✓ Branch 84 → 128 taken 1 time.
111 impl->object_bindings.push_back({object, current_vptr});
4050 110 const std::string_view created_name = impl->name;
4051 const std::optional<std::uint64_t> recorded =
4052 110 DetourModKit::detail::HookLedger::instance().try_record_vmt(cloned_vptr_base);
4053
1/2
✗ Branch 90 → 91 not taken.
✓ Branch 90 → 94 taken 110 times.
110 if (!recorded)
4054 {
4055 ✗ return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::vmt_for"});
4056 }
4057 110 impl->ledger_id = *recorded;
4058 // Publication is last: every allocation, binding, and ledger step completes before the guarded store
4059 // can expose the clone to host dispatch.
4060
2/2
✓ Branch 97 → 98 taken 4 times.
✓ Branch 97 → 104 taken 106 times.
110 if (!publish_vmt_object_word(object, current_vptr, cloned_vptr_base))
4061 {
4062 4 DetourModKit::detail::HookLedger::instance().release_vmt(*recorded);
4063 4 return std::unexpected(
4064 4 Error{ErrorCode::InvalidObject, "hook::vmt_for", reinterpret_cast<std::uintptr_t>(object)}
4065 4 );
4066 }
4067 // Release the gate BEFORE the log and lifecycle event: subscriber code must not run under the
4068 // process-wide VMT mutex (CP.22), because a reentrant subscriber self-deadlocks.
4069
1/2
✓ Branch 104 → 105 taken 106 times.
✗ Branch 104 → 129 not taken.
106 object_gate.unlock();
4070 106 report_vmt_hook_created(created_name, *recorded, object);
4071 // Hand the module reference to the Impl only after completion of every fallible setup step.
4072 106 impl->self_ref = self_ref.release();
4073 106 return VmtHook(std::move(impl));
4074 114 }
4075
1/2
✓ Branch 134 → 135 taken 9 times.
✗ Branch 134 → 139 not taken.
9 catch (const std::bad_alloc &)
4076 {
4077 9 return std::unexpected(Error{ErrorCode::OutOfMemory, "hook::vmt_for"});
4078 9 }
4079 ✗ catch (...)
4080 {
4081 ✗ return std::unexpected(Error{ErrorCode::UnknownError, "hook::vmt_for"});
4082
0/2
✗ Branch 142 → 120 not taken.
✗ Branch 142 → 143 not taken.
✗ }
4083 145 }
4084 } // namespace hook
4085 } // namespace DetourModKit
4086