Skip to content

Commit 5260a10

Browse files
committed
Enforce signature invariants in bytes_to_signature and string_to_signature
1 parent 4b5a34c commit 5260a10

File tree

2 files changed

+33
-31
lines changed

2 files changed

+33
-31
lines changed

include/libhat/signature.hpp

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,29 @@ LIBHAT_EXPORT namespace hat {
8888
template<size_t N>
8989
using fixed_signature = std::array<signature_element, N>;
9090

91+
enum class signature_error {
92+
missing_masked_byte,
93+
element_parse_error,
94+
empty_signature,
95+
expected_wildcard,
96+
invalid_token_length,
97+
illegal_first_byte,
98+
};
99+
91100
/// Convert raw byte storage into a signature
92-
template<size_t N>
101+
template<size_t N> requires (N != std::dynamic_extent && N > 0)
93102
[[nodiscard]] constexpr auto bytes_to_signature(std::span<const std::byte, N> bytes) {
94-
if constexpr (N == std::dynamic_extent) {
95-
return signature{bytes.begin(), bytes.end()};
96-
} else {
97-
fixed_signature<N> result;
98-
std::ranges::copy(bytes, result.begin());
99-
return result;
103+
fixed_signature<N> result;
104+
std::ranges::copy(bytes, result.begin());
105+
return result;
106+
}
107+
108+
/// Convert raw byte storage into a signature
109+
[[nodiscard]] LIBHAT_CONSTEXPR_RESULT result<signature, signature_error> bytes_to_signature(std::span<const std::byte> bytes) {
110+
if (bytes.empty()) {
111+
return result_error{signature_error::empty_signature};
100112
}
113+
return signature{bytes.begin(), bytes.end()};
101114
}
102115

103116
template<typename T>
@@ -112,27 +125,16 @@ LIBHAT_EXPORT namespace hat {
112125
}
113126

114127
template<typename Char>
115-
[[nodiscard]] constexpr signature string_to_signature(std::basic_string_view<Char> str) {
128+
[[nodiscard]] constexpr result<signature, signature_error> string_to_signature(std::basic_string_view<Char> str) {
116129
const auto bytes = std::as_bytes(std::span{str});
117-
signature sig{};
118-
sig.reserve(bytes.size());
119-
for (std::byte byte : bytes) {
120-
sig.emplace_back(byte);
121-
}
122-
return sig;
130+
return bytes_to_signature(bytes);
123131
}
124132

125133
template<typename Char>
126-
[[nodiscard]] constexpr signature string_to_signature(std::basic_string<Char> str) {
134+
[[nodiscard]] constexpr result<signature, signature_error> string_to_signature(std::basic_string<Char> str) {
127135
return string_to_signature(std::basic_string_view<Char>{str});
128136
}
129137

130-
enum class signature_parse_error {
131-
missing_byte,
132-
parse_error,
133-
empty_signature,
134-
};
135-
136138
namespace detail {
137139

138140
LIBHAT_CONSTEXPR_RESULT std::optional<signature_element> parse_signature_element(const std::string_view str, const uint8_t base) {
@@ -155,7 +157,7 @@ LIBHAT_EXPORT namespace hat {
155157
}
156158
}
157159

158-
[[nodiscard]] LIBHAT_CONSTEXPR_RESULT result<size_t, signature_parse_error> parse_signature_to(std::output_iterator<signature_element> auto out, const std::string_view str) {
160+
[[nodiscard]] LIBHAT_CONSTEXPR_RESULT result<size_t, signature_error> parse_signature_to(std::output_iterator<signature_element> auto out, const std::string_view str) {
159161
size_t written = 0;
160162
bool containsByte = false;
161163

@@ -167,7 +169,7 @@ LIBHAT_EXPORT namespace hat {
167169
}
168170
case 1: {
169171
if (word.front() != '?') {
170-
return result_error{signature_parse_error::parse_error};
172+
return result_error{signature_error::expected_wildcard};
171173
}
172174
*out++ = signature_element{std::nullopt};
173175
written++;
@@ -183,30 +185,30 @@ LIBHAT_EXPORT namespace hat {
183185

184186
if (!containsByte && element->any()) {
185187
if (!element->all()) {
186-
return result_error{signature_parse_error::missing_byte};
188+
return result_error{signature_error::illegal_first_byte};
187189
}
188190
containsByte = true;
189191
}
190192
} else {
191-
return result_error{signature_parse_error::parse_error};
193+
return result_error{signature_error::element_parse_error};
192194
}
193195
break;
194196
}
195197
default: {
196-
return result_error{signature_parse_error::parse_error};
198+
return result_error{signature_error::invalid_token_length};
197199
}
198200
}
199201
}
200202
if (written == 0) {
201-
return result_error{signature_parse_error::empty_signature};
203+
return result_error{signature_error::empty_signature};
202204
}
203205
if (!containsByte) {
204-
return result_error{signature_parse_error::missing_byte};
206+
return result_error{signature_error::missing_masked_byte};
205207
}
206208
return written;
207209
}
208210

209-
[[nodiscard]] LIBHAT_CONSTEXPR_RESULT result<signature, signature_parse_error> parse_signature(std::string_view str) {
211+
[[nodiscard]] LIBHAT_CONSTEXPR_RESULT result<signature, signature_error> parse_signature(std::string_view str) {
210212
signature sig{};
211213
auto result = parse_signature_to(std::back_inserter(sig), str);
212214

src/os/win32/Scanner.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace hat::experimental {
99
scan_result find_vtable<compiler_type::MSVC>(const std::string& className, hat::process::module mod) {
1010
// Tracing cross-references
1111
// Type Descriptor => Object Locator => VTable
12-
auto sig = string_to_signature(".?AV" + className + "@@");
12+
auto sig = string_to_signature(".?AV" + className + "@@").value();
1313

1414
// TODO: Have a better solution for this
1515
// 3rd character may be 'V' for classes and 'U' for structs
@@ -53,7 +53,7 @@ namespace hat::experimental {
5353
scan_result find_vtable<compiler_type::GNU>(const std::string& className, hat::process::module mod) {
5454
// Tracing cross-references
5555
// Type Descriptor Name => Type Info => VTable
56-
const auto sig = string_to_signature(std::to_string(className.size()) + className + "\0");
56+
const auto sig = string_to_signature(std::to_string(className.size()) + className + "\0").value();
5757
const auto typeName = *find_pattern(sig, ".rdata", mod);
5858
if (!typeName) {
5959
return nullptr;

0 commit comments

Comments
 (0)