From 1f58e91d60f43d9e403d19528f0d0ddeb2463877 Mon Sep 17 00:00:00 2001 From: pucedoteth <119044801+pucedoteth@users.noreply.github.com> Date: Sat, 29 Aug 2026 04:38:57 +0200 Subject: [PATCH] epee, common: pass unsigned char to functions The functions require their argument to be representable as unsigned char or to equal EOF. char is signed on the platforms Monero targets, so every byte >= 0x80 reaches them negative, which is undefined behaviour. All six call sites take bytes that come from outside the process: hex_to_dec_2bytes() percent-escapes in a payment URI http_client.h the status line of an HTTP response updates.cpp the hash field of a DNS update record glibc and the macOS libc happen to tolerate -128..-1 because their tables carry padding below zero, so this is quiet in practice on those, but it is still out of contract and other libcs index without that cushion. Cast to unsigned char at each call. The conversion is behaviour-preserving for the ASCII these actually test: for a byte such as 0xC3, toupper() returns it unchanged in the C locale, it narrows back to char, memchr() misses it in the hex table, and hex_to_dec_2bytes() falls through to the existing literal "%XY" output exactly as before. epee::misc_utils::parse::isdigit/isalpha/isspace are separate char-taking helpers and are already well defined, so they are untouched, as is is_base64(), which already takes unsigned char. --- contrib/epee/include/net/http_client.h | 6 +++--- contrib/epee/src/abstract_http_client.cpp | 4 ++-- src/common/updates.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index 6396bbe6f..6e49f5f42 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -662,14 +662,14 @@ namespace net_utils ptr = end + 1; CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr); ul = strtoul(ptr, &end, 10); - CHECK_AND_ASSERT_MES(ul <= INT_MAX && isblank(*end), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr); + CHECK_AND_ASSERT_MES(ul <= INT_MAX && isblank(static_cast(*end)), false, "Invalid first response line: " + m_header_cache + ", ptr: " << ptr); m_response_info.m_http_ver_lo = ul; ptr = end + 1; - while (isblank(*ptr)) + while (isblank(static_cast(*ptr))) ++ptr; CHECK_AND_ASSERT_MES(epee::misc_utils::parse::isdigit(*ptr), false, "Invalid first response line: " + m_header_cache); ul = strtoul(ptr, &end, 10); - CHECK_AND_ASSERT_MES(ul >= 100 && ul <= 999 && isspace(*end), false, "Invalid first response line: " + m_header_cache); + CHECK_AND_ASSERT_MES(ul >= 100 && ul <= 999 && isspace(static_cast(*end)), false, "Invalid first response line: " + m_header_cache); m_response_info.m_response_code = ul; ptr = end; // ignore the optional text, till the end diff --git a/contrib/epee/src/abstract_http_client.cpp b/contrib/epee/src/abstract_http_client.cpp index bd9cb0dde..dd3763ad1 100644 --- a/contrib/epee/src/abstract_http_client.cpp +++ b/contrib/epee/src/abstract_http_client.cpp @@ -65,8 +65,8 @@ namespace net_utils std::string hex_to_dec_2bytes(const char *s) { const char *hex = get_hex_vals(); - int i0 = get_index(hex, toupper(s[0])); - int i1 = get_index(hex, toupper(s[1])); + int i0 = get_index(hex, toupper(static_cast(s[0]))); + int i1 = get_index(hex, toupper(static_cast(s[1]))); if (i0 < 0 || i1 < 0) return std::string("%") + std::string(1, s[0]) + std::string(1, s[1]); return std::string(1, i0 * 16 | i1); diff --git a/src/common/updates.cpp b/src/common/updates.cpp index a8202b0d5..6c445ca54 100644 --- a/src/common/updates.cpp +++ b/src/common/updates.cpp @@ -73,7 +73,7 @@ namespace tools bool alnum = true; for (auto c: fields[3]) - if (!isalnum(c)) + if (!isalnum(static_cast(c))) alnum = false; if (fields[3].size() != 64 && !alnum) {