GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 91.7% 22 / 0 / 24
Functions: 100.0% 2 / 0 / 2
Branches: 83.3% 10 / 0 / 12

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 7347 snapshot_lifecycle(const std::string &name, std::uint64_t ledger_id, bool is_inline) noexcept
41 {
42 7347 LifecycleSnapshot snapshot;
43 7347 snapshot.ledger_id = ledger_id;
44
2/2
✓ Branch 3 → 4 taken 7278 times.
✓ Branch 3 → 5 taken 69 times.
7347 snapshot.kind = is_inline ? diagnostics::HookKind::Inline : diagnostics::HookKind::Mid;
45 try
46 {
47
2/2
✓ Branch 6 → 7 taken 7346 times.
✓ Branch 6 → 9 taken 1 time.
7347 snapshot.name = name;
48 }
49 1 catch (...)
50 {
51 1 }
52 7347 return snapshot;
53 }
54
55 /**
56 * @brief Updates the live population tally, then emits the associated hook lifecycle event.
57 * @param removal Population state for a Removed event. Teardown must capture @c was_active before it forces its
58 * status to Disabled. Set @c remains_live when the target stays conservatively tracked.
59 * @details The tally moves first so a subscriber that calls collect() observes the completed transition.
60 */
61 8544 inline void emit_lifecycle(
62 std::string_view name,
63 std::uint64_t ledger_id,
64 diagnostics::HookKind kind,
65 diagnostics::HookTransition transition,
66 RemovalPopulationState removal = {}
67 ) noexcept
68 {
69
3/4
✓ Branch 2 → 3 taken 608 times.
✓ Branch 2 → 5 taken 7347 times.
✓ Branch 2 → 6 taken 589 times.
✗ Branch 2 → 9 not taken.
8544 switch (transition)
70 {
71 608 case diagnostics::HookTransition::Created:
72 608 DetourModKit::detail::hook_population::record_created(kind == diagnostics::HookKind::Vmt);
73 608 break;
74 7347 case diagnostics::HookTransition::Enabled:
75 case diagnostics::HookTransition::Disabled:
76 // The status store updates the count while it still holds the call gate. This code runs after unlock.
77 // Otherwise, two toggles can commit +1/-1 in an order opposite their serialized transitions.
78 7347 break;
79 589 case diagnostics::HookTransition::Removed:
80
2/2
✓ Branch 6 → 7 taken 570 times.
✓ Branch 6 → 8 taken 19 times.
589 if (!removal.remains_live)
81 {
82 570 DetourModKit::detail::hook_population::record_removed(removal.was_active);
83 }
84 589 break;
85 }
86 try
87 {
88
1/2
✓ Branch 9 → 10 taken 8544 times.
✗ Branch 9 → 13 not taken.
8544 diagnostics::hook_lifecycle().emit_safe(
89 8544 diagnostics::HookLifecycleEvent{
90 .name = name,
91 .ledger_id = ledger_id,
92 .kind = kind,
93 .transition = transition,
94 }
95 );
96 }
97 catch (...)
98 {
99 }
100 8544 }
101 } // namespace DetourModKit::detail
102
103 #endif // DETOURMODKIT_INTERNAL_HOOK_EMISSION_HPP
104