From 39d4b41e2becbebb431c22dd1bf4cab5d5e5661a Mon Sep 17 00:00:00 2001 From: udo Date: Sat, 18 Jul 2026 16:22:14 +0000 Subject: [PATCH] Reject negative unsigned string values --- site/doc/pages/to_u64.txt | 3 ++- site/tests/io.uce | 1 + src/lib/functionlib.cpp | 15 ++++++++++++--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/site/doc/pages/to_u64.txt b/site/doc/pages/to_u64.txt index ead893a..6646138 100644 --- a/site/doc/pages/to_u64.txt +++ b/site/doc/pages/to_u64.txt @@ -14,7 +14,8 @@ to_bool int_val :content -Parses a trimmed string as a base-10 unsigned integer. +Parses a trimmed string as a base-10 unsigned integer. An optional leading `+` +is accepted. Negative and overflowing values return the fallback. Unlike `int_val()`, the whole trimmed string must be consumed by the parser. Empty strings and partially parsed values such as `"42px"` return the fallback. diff --git a/site/tests/io.uce b/site/tests/io.uce index 45cd819..e527bbe 100644 --- a/site/tests/io.uce +++ b/site/tests/io.uce @@ -149,6 +149,7 @@ RENDER(Request& context) cfg["yes"] = "yes"; cfg["no"] = "off"; check("to_u64() / to_s64() / to_f64() / to_bool()", to_u64(cfg["u64"], 7) == 42 && to_u64(cfg["bad"], 7) == 7 && to_s64(cfg["s64"], 5) == -12 && to_s64(cfg["bad"], 5) == 5 && to_f64(cfg["f64"], 1.0) > 3.49 && to_f64(cfg["bad"], 1.25) == 1.25 && to_bool(cfg["yes"], false) && !to_bool(cfg["no"], true) && !to_bool("unknown", false), var_dump(cfg)); + check("to_u64() rejects negative and overflowing text", to_u64("-1", 7) == 7 && to_u64("+42", 7) == 42 && to_u64("18446744073709551615", 7) == 18446744073709551615ULL && to_u64("18446744073709551616", 7) == 7, std::to_string(to_u64("-1", 7)) + "/" + std::to_string(to_u64("18446744073709551616", 7))); DValue perf = request_perf(); u64 module_misses = perf["unit_module_cache_miss_count"].to_u64(); diff --git a/src/lib/functionlib.cpp b/src/lib/functionlib.cpp index e105631..aea7d0e 100644 --- a/src/lib/functionlib.cpp +++ b/src/lib/functionlib.cpp @@ -929,9 +929,18 @@ u64 to_u64(String s, u64 fallback) String raw = trim(s); if(raw == "") return(fallback); - char* end = 0; - unsigned long long value = strtoull(raw.c_str(), &end, 10); - return(end && *end == 0 ? (u64)value : fallback); + u64 value = 0; + u64 offset = raw[0] == '+' ? 1 : 0; + if(offset == raw.size()) + return(fallback); + for(; offset < raw.size(); offset++) + { + char c = raw[offset]; + if(c < '0' || c > '9' || value > (UINT64_MAX - (u64)(c - '0')) / 10) + return(fallback); + value = value * 10 + (u64)(c - '0'); + } + return(value); } s64 to_s64(String s, s64 fallback)