GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 95.6% 43 / 0 / 45
Functions: 100.0% 4 / 0 / 4
Branches: 77.6% 38 / 0 / 49

src/internal/hook_patch_witness.hpp
Line Branch Exec Source
1 #ifndef DETOURMODKIT_INTERNAL_HOOK_PATCH_WITNESS_HPP
2 #define DETOURMODKIT_INTERNAL_HOOK_PATCH_WITNESS_HPP
3
4 /**
5 * @file hook_patch_witness.hpp
6 * @brief Four-state ownership witness for inline-hook patch windows.
7 */
8
9 #include "internal/hook_fault_boundary.hpp"
10 #include "internal/memory_guarded.hpp"
11
12 #include <algorithm>
13 #include <array>
14 #include <cstddef>
15 #include <cstdint>
16 #include <string_view>
17
18 namespace DetourModKit::detail
19 {
20 /**
21 * @brief Who owns the bytes currently at an inline backend's patch window.
22 * @details Original means no patch is installed; OwnedPatch means the bytes exactly match an encoding this backend
23 * committed; Foreign means the readable window matches neither; Indeterminate means it could not be read.
24 */
25 enum class PatchWitness : std::uint8_t
26 {
27 Original,
28 OwnedPatch,
29 Foreign,
30 Indeterminate
31 };
32
33 /// Names a patch witness for an operator-facing diagnostic.
34 43 [[nodiscard]] constexpr std::string_view witness_description(PatchWitness witness) noexcept
35 {
36
4/5
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 4 taken 22 times.
✓ Branch 2 → 5 taken 12 times.
✓ Branch 2 → 6 taken 5 times.
✗ Branch 2 → 7 not taken.
43 switch (witness)
37 {
38 4 case PatchWitness::Original:
39 4 return "prologue is original";
40 22 case PatchWitness::OwnedPatch:
41 22 return "our patch is still installed";
42 12 case PatchWitness::Foreign:
43 12 return "another writer owns the prologue";
44 5 case PatchWitness::Indeterminate:
45 5 break;
46 }
47 5 return "prologue could not be read";
48 }
49
50 /**
51 * @brief Reads a backend target and classifies ownership of its patch window.
52 * @details OwnedPatch requires both exact bytes and persistent provenance that the backend completed a patch-byte
53 * capture. Pre-sized or default-initialized storage is not evidence that the backend emitted those bytes.
54 */
55 17341 template <class Backend> [[nodiscard]] PatchWitness witness_patch(const Backend &backend) noexcept
56 {
57 17341 const auto &original = backend.original_bytes();
58 17341 std::array<std::uint8_t, BACKEND_MAX_STEAL_WINDOW> current{};
59
8/16
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::InlineHook>(safetyhook::InlineHook const&):
✓ Branch 4 → 5 taken 16743 times.
✗ Branch 4 → 11 not taken.
✓ Branch 8 → 9 taken 16743 times.
✗ Branch 8 → 11 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 16743 times.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 16743 times.
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::MidHook>(safetyhook::MidHook const&):
✓ Branch 4 → 5 taken 598 times.
✗ Branch 4 → 11 not taken.
✓ Branch 8 → 9 taken 598 times.
✗ Branch 8 → 11 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 598 times.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 598 times.
34682 if (original.empty() || original.size() > current.size() || backend.target() == nullptr)
60 {
61 return PatchWitness::Indeterminate;
62 }
63 17341 const std::size_t count = original.size();
64
4/4
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::InlineHook>(safetyhook::InlineHook const&):
✓ Branch 20 → 21 taken 7 times.
✓ Branch 20 → 22 taken 16736 times.
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::MidHook>(safetyhook::MidHook const&):
✓ Branch 20 → 21 taken 1 time.
✓ Branch 20 → 22 taken 597 times.
17341 if (!guarded_read_bytes(reinterpret_cast<std::uintptr_t>(backend.target()), current.data(), count))
65 {
66 8 return PatchWitness::Indeterminate;
67 }
68 17333 const auto span = static_cast<std::ptrdiff_t>(count);
69
4/4
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::InlineHook>(safetyhook::InlineHook const&):
✓ Branch 29 → 30 taken 8100 times.
✓ Branch 29 → 31 taken 8636 times.
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::MidHook>(safetyhook::MidHook const&):
✓ Branch 29 → 30 taken 464 times.
✓ Branch 29 → 31 taken 133 times.
34666 if (std::equal(original.begin(), original.begin() + span, current.begin()))
70 {
71 8564 return PatchWitness::Original;
72 }
73 8769 const auto &emitted = backend.patch_bytes();
74
6/8
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::InlineHook>(safetyhook::InlineHook const&):
✓ Branch 33 → 34 taken 8633 times.
✓ Branch 33 → 45 taken 3 times.
✓ Branch 35 → 36 taken 8633 times.
✗ Branch 35 → 45 not taken.
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::MidHook>(safetyhook::MidHook const&):
✓ Branch 33 → 34 taken 132 times.
✓ Branch 33 → 45 taken 1 time.
✓ Branch 35 → 36 taken 132 times.
✗ Branch 35 → 45 not taken.
17534 if (backend.patch_bytes_valid() && emitted.size() == count &&
75
8/8
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::InlineHook>(safetyhook::InlineHook const&):
✓ Branch 43 → 44 taken 8610 times.
✓ Branch 43 → 45 taken 23 times.
✓ Branch 46 → 47 taken 8610 times.
✓ Branch 46 → 48 taken 26 times.
DetourModKit::detail::PatchWitness DetourModKit::detail::witness_patch<safetyhook::MidHook>(safetyhook::MidHook const&):
✓ Branch 43 → 44 taken 131 times.
✓ Branch 43 → 45 taken 1 time.
✓ Branch 46 → 47 taken 131 times.
✓ Branch 46 → 48 taken 2 times.
26299 std::equal(emitted.begin(), emitted.begin() + span, current.begin()))
76 {
77 8741 return PatchWitness::OwnedPatch;
78 }
79 28 return PatchWitness::Foreign;
80 }
81
82 /// Returns whether a witness authorizes the backend to overwrite the target.
83 8633 [[nodiscard]] constexpr bool witness_permits_write(PatchWitness witness) noexcept
84 {
85
4/4
✓ Branch 2 → 3 taken 4244 times.
✓ Branch 2 → 4 taken 4389 times.
✓ Branch 3 → 4 taken 4221 times.
✓ Branch 3 → 5 taken 23 times.
8633 return witness == PatchWitness::Original || witness == PatchWitness::OwnedPatch;
86 }
87 } // namespace DetourModKit::detail
88
89 #endif // DETOURMODKIT_INTERNAL_HOOK_PATCH_WITNESS_HPP
90