GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 25 / 0 / 25
Functions: 100.0% 6 / 0 / 6
Branches: 66.7% 16 / 0 / 24

src/diagnostics.cpp
Line Branch Exec Source
1 /**
2 * @file diagnostics.cpp
3 * @brief Process-wide counters for DMK's intentional leak / detach paths.
4 */
5
6 #include "DetourModKit/diagnostics.hpp"
7
8 #include <array>
9 #include <atomic>
10 #include <cstddef>
11
12 namespace DetourModKit
13 {
14 namespace Diagnostics
15 {
16 namespace
17 {
18 constexpr std::size_t LEAK_SUBSYSTEM_COUNT = static_cast<std::size_t>(LeakSubsystem::Count);
19
20 // One independent event tally per subsystem. Relaxed throughout: the counters carry no ordering obligation
21 // toward any other state, and each leak site fires at most once per process, so there is no meaningful
22 // contention to order.
23 std::array<std::atomic<std::size_t>, LEAK_SUBSYSTEM_COUNT> s_leak_counts{};
24 } // namespace
25
26 21 void record_intentional_leak(LeakSubsystem subsystem) noexcept
27 {
28 21 const auto index = static_cast<std::size_t>(subsystem);
29
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 20 times.
21 if (index >= LEAK_SUBSYSTEM_COUNT)
30 {
31 1 return;
32 }
33 20 s_leak_counts[index].fetch_add(1, std::memory_order_relaxed);
34 }
35
36 49 std::size_t intentional_leak_count(LeakSubsystem subsystem) noexcept
37 {
38 49 const auto index = static_cast<std::size_t>(subsystem);
39
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 48 times.
49 if (index >= LEAK_SUBSYSTEM_COUNT)
40 {
41 1 return 0;
42 }
43 96 return s_leak_counts[index].load(std::memory_order_relaxed);
44 }
45
46 11 std::size_t total_intentional_leaks() noexcept
47 {
48 11 std::size_t total = 0;
49
2/2
✓ Branch 11 → 3 taken 88 times.
✓ Branch 11 → 12 taken 11 times.
99 for (const auto &counter : s_leak_counts)
50 {
51 176 total += counter.load(std::memory_order_relaxed);
52 }
53 11 return total;
54 }
55
56 23 void reset_intentional_leaks() noexcept
57 {
58
2/2
✓ Branch 12 → 3 taken 184 times.
✓ Branch 12 → 13 taken 23 times.
207 for (auto &counter : s_leak_counts)
59 {
60 184 counter.store(0, std::memory_order_relaxed);
61 }
62 23 }
63
64 3516 EventDispatcher<ScannerFaultEvent> &scanner_faults()
65 {
66 // Function-local static: a single process-wide dispatcher constructed on first use, so the stateless
67 // scanner and any consumer share the same subscriber set without a static-init-order dependency.
68
4/8
✓ Branch 2 → 3 taken 5 times.
✓ Branch 2 → 8 taken 3511 times.
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 10 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
3516 static EventDispatcher<ScannerFaultEvent> dispatcher;
69 3516 return dispatcher;
70 }
71
72 303 EventDispatcher<HookLifecycleEvent> &hook_lifecycle()
73 {
74
4/8
✓ Branch 2 → 3 taken 118 times.
✓ Branch 2 → 8 taken 185 times.
✓ Branch 4 → 5 taken 118 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 118 times.
✗ Branch 5 → 10 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
303 static EventDispatcher<HookLifecycleEvent> dispatcher;
75 303 return dispatcher;
76 }
77 } // namespace Diagnostics
78 } // namespace DetourModKit
79