./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
25 / 27
92.6%
Branches:
10 / 12
83.3%
Functions:
3 / 3
100.0%

src/internal/hook_emission.hpp
Line Branch Exec Source
1 #ifndef DETOURMODKIT_INTERNAL_HOOK_EMISSION_HPP
2 #define DETOURMODKIT_INTERNAL_HOOK_EMISSION_HPP
3
4 /**
5 * @file internal/hook_emission.hpp
6 * @brief The shared hook lifecycle snapshot and emission sequence for the hook sibling TUs.
7 * @details src/hook.cpp and src/hook_toggle.cpp publish lifecycle events through this one sequence, so the
8 * population-then-emit order and the owned-name lifetime rule are stated exactly once.
9 */
10
11 #include "DetourModKit/diagnostics.hpp"
12
13 #include "internal/diagnostics_population.hpp"
14
15 #include <cstdint>
16 #include <string>
17 #include <string_view>
18
19 namespace DetourModKit::detail
20 {
21 struct RemovalPopulationState
22 {
23 bool was_active{false};
24 bool remains_live{false};
25 };
26
27 /**
28 * @brief Owns the identity for one enable or disable lifecycle event.
29 * @details The owned name stays valid if a subscriber destroys the hook before synchronous emission ends. A
30 * failed name copy preserves the transition and publishes an empty name (HookLifecycleName.*).
31 */
32 struct LifecycleSnapshot
33 {
34 std::string name;
35 std::uint64_t ledger_id{0};
36 diagnostics::HookKind kind{diagnostics::HookKind::Inline};
37 };
38
39 [[nodiscard]] inline LifecycleSnapshot
40 18139 snapshot_lifecycle(const std::string &name, std::uint64_t ledger_id, bool is_inline) noexcept
41 {
42 18139 LifecycleSnapshot snapshot;
43 18139 snapshot.ledger_id = ledger_id;
44
2/2
✓ Branch 3 → 4 taken 15037 times.
✓ Branch 3 → 5 taken 3102 times.
18139 snapshot.kind = is_inline ? diagnostics::HookKind::Inline : diagnostics::HookKind::Mid;
45 try
46 {
47
2/2
✓ Branch 6 → 7 taken 18138 times.
✓ Branch 6 → 9 taken 1 time.
18139 snapshot.name = name;
48 }
49 1 catch (...)
50 {
51 1 }
52 18139 return snapshot;
53 }
54
55 /// Emits one hook lifecycle event and contains a subscriber failure. It moves no population tally.
56 56214 inline void emit_lifecycle_event(
57 std::string_view name,
58 std::uint64_t ledger_id,
59 diagnostics::HookKind kind,
60 diagnostics::HookTransition transition
61 ) noexcept
62 {
63 try
64 {
65
1/2
✓ Branch 2 → 3 taken 56214 times.
✗ Branch 2 → 6 not taken.
56214 diagnostics::hook_lifecycle().emit_safe(
66 56214 diagnostics::HookLifecycleEvent{
67 .name = name,
68 .ledger_id = ledger_id,
69 .kind = kind,
70 .transition = transition,
71 }
72 );
73 }
74 ✗ catch (...)
75 {
76 ✗ }
77 56216 }
78
79 /**
80 * @brief Updates the live population tally, then emits the associated hook lifecycle event.
81 * @param removal Population state for a Removed event. Teardown must capture @c was_active before it forces its
82 * status to Disabled. Set @c remains_live when the detour stays reachable. A residue keeps
83 * the target tracked but leaves the live population.
84 * @details The tally moves first so a subscriber that calls collect() observes the completed transition.
85 */
86 47759 inline void emit_lifecycle(
87 std::string_view name,
88 std::uint64_t ledger_id,
89 diagnostics::HookKind kind,
90 diagnostics::HookTransition transition,
91 RemovalPopulationState removal = {}
92 ) noexcept
93 {
94
3/4
✓ Branch 2 → 3 taken 12706 times.
✓ Branch 2 → 5 taken 18139 times.
✓ Branch 2 → 6 taken 16915 times.
✗ Branch 2 → 9 not taken.
47759 switch (transition)
95 {
96 12706 case diagnostics::HookTransition::Created:
97 12706 DetourModKit::detail::hook_population::record_created(kind == diagnostics::HookKind::Vmt);
98 12706 break;
99 18139 case diagnostics::HookTransition::Enabled:
100 case diagnostics::HookTransition::Disabled:
101 // The status store updates the count while it still holds the call gate. This code runs after unlock.
102 // Otherwise, two toggles can commit +1/-1 in an order opposite their serialized transitions.
103 18139 break;
104 16915 case diagnostics::HookTransition::Removed:
105
2/2
✓ Branch 6 → 7 taken 16899 times.
✓ Branch 6 → 8 taken 16 times.
16915 if (!removal.remains_live)
106 {
107 16899 DetourModKit::detail::hook_population::record_removed(removal.was_active);
108 }
109 16915 break;
110 }
111 47759 emit_lifecycle_event(name, ledger_id, kind, transition);
112 47755 }
113 } // namespace DetourModKit::detail
114
115 #endif // DETOURMODKIT_INTERNAL_HOOK_EMISSION_HPP
116