src/region.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "DetourModKit/region.hpp" | ||
| 2 | |||
| 3 | #include "internal/memory_guarded.hpp" | ||
| 4 | #include "internal/module_name.hpp" | ||
| 5 | |||
| 6 | #include <windows.h> | ||
| 7 | |||
| 8 | #include <cstddef> | ||
| 9 | #include <cstdint> | ||
| 10 | #include <string> | ||
| 11 | |||
| 12 | namespace DetourModKit | ||
| 13 | { | ||
| 14 | 176 | Region Region::host() noexcept | |
| 15 | { | ||
| 16 | // GetModuleHandleW(nullptr) returns the base of the process image (the host .exe the mod DLL was injected | ||
| 17 | // into), which is the default scan scope for a cascade that carries no explicit range. The base is resolved | ||
| 18 | // to a full image span by the shared guarded PE resolver. | ||
| 19 | 176 | return detail::module_image_region(Address{::GetModuleHandleW(nullptr)}); | |
| 20 | } | ||
| 21 | |||
| 22 | 7 | Region Region::own() noexcept | |
| 23 | { | ||
| 24 | // Resolve the module that contains this function's own code. Because DetourModKit is a static library, the | ||
| 25 | // address of Region::own lands inside whichever DLL/EXE linked it, so GetModuleHandleExW(FROM_ADDRESS, ...) | ||
| 26 | // returns that consumer module rather than the process EXE. FROM_ADDRESS plus UNCHANGED_REFCOUNT looks the | ||
| 27 | // handle up without taking a reference, matching the transient-scope contract every Region factory keeps. | ||
| 28 | 7 | HMODULE owning_module = nullptr; | |
| 29 | 7 | if (!::GetModuleHandleExW( | |
| 30 | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, | ||
| 31 | reinterpret_cast<LPCWSTR>(&Region::own), | ||
| 32 | &owning_module | ||
| 33 |
2/4✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 5 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 7 times.
|
14 | ) || |
| 34 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7 times.
|
7 | owning_module == nullptr) |
| 35 | { | ||
| 36 | ✗ | return Region{}; | |
| 37 | } | ||
| 38 | 7 | return detail::module_image_region(Address{owning_module}); | |
| 39 | } | ||
| 40 | |||
| 41 | 143 | Region Region::module_named(std::string_view name) noexcept | |
| 42 | { | ||
| 43 | // Invalid names and conversion failures take the same fail-closed path as an unloaded module. | ||
| 44 | 143 | const std::wstring wide_name = detail::widen_module_name(name); | |
| 45 |
2/2✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 7 taken 141 times.
|
143 | if (wide_name.empty()) |
| 46 | { | ||
| 47 | 2 | return Region{}; | |
| 48 | } | ||
| 49 | |||
| 50 | // GetModuleHandleW does not add a reference, so the returned handle is only valid while the module stays | ||
| 51 | // loaded. That is the correct contract here: a Region is a transient scan scope, not an ownership claim. | ||
| 52 | 141 | return detail::module_image_region(Address{::GetModuleHandleW(wide_name.c_str())}); | |
| 53 | 143 | } | |
| 54 | |||
| 55 | 9 | Region Region::whole_process() noexcept | |
| 56 | { | ||
| 57 | // Span the user-mode virtual-address window the OS reports for this process rather than hardcoding the | ||
| 58 | // canonical x64 0x7FFF'FFFFFFFF ceiling, so the Region stays correct regardless of address-layout settings. | ||
| 59 | 9 | SYSTEM_INFO system_info{}; | |
| 60 | 9 | ::GetSystemInfo(&system_info); | |
| 61 | |||
| 62 | 9 | const auto minimum_address = reinterpret_cast<std::uintptr_t>(system_info.lpMinimumApplicationAddress); | |
| 63 | 9 | const auto maximum_address = reinterpret_cast<std::uintptr_t>(system_info.lpMaximumApplicationAddress); | |
| 64 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 9 times.
|
9 | if (maximum_address <= minimum_address) |
| 65 | { | ||
| 66 | ✗ | return Region{}; | |
| 67 | } | ||
| 68 | |||
| 69 | // lpMaximumApplicationAddress is the highest address usable by the process and is INCLUSIVE, so the half-open | ||
| 70 | // Region must run one byte past it to actually contain that last address: size = (max - min) + 1. The guard | ||
| 71 | // above guarantees max > min, and an application maximum is never UINTPTR_MAX, so the + 1 cannot overflow. | ||
| 72 | 9 | return Region{Address{minimum_address}, static_cast<std::size_t>(maximum_address - minimum_address) + 1U}; | |
| 73 | } | ||
| 74 | } // namespace DetourModKit | ||
| 75 |