From 09efc2b60080ce2fce7ef4f80129e71ec5e0f920 Mon Sep 17 00:00:00 2001 From: jdymitarai Date: Thu, 10 Sep 2026 11:10:50 +0800 Subject: [PATCH] Fix undefined behavior in StringView trimming and validate positive number parsing 1. Cast char to (unsigned char) in CpuFeatures_StringView_TrimWhitespace before calling isspace() to prevent undefined behavior with negative char values on platforms with signed char. 2. Reject empty views in ParsePositiveNumberWithBase, ensuring incomplete hex prefixes such as '0x' return -1 instead of erroneously returning 0. 3. Check for signed integer overflow in ParsePositiveNumberWithBase before multiplication. 4. Add comprehensive unit tests in string_view_test.cc covering non-ASCII whitespace trimming, hex validation, and integer overflow. --- src/string_view.c | 11 ++++++++--- test/string_view_test.cc | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/string_view.c b/src/string_view.c index 554294fa..bf6d7415 100644 --- a/src/string_view.c +++ b/src/string_view.c @@ -16,6 +16,7 @@ #include #include +#include #include "copy.inl" #include "equals.inl" @@ -101,9 +102,11 @@ char CpuFeatures_StringView_Back(const StringView view) { } StringView CpuFeatures_StringView_TrimWhitespace(StringView view) { - while (view.size && isspace(CpuFeatures_StringView_Front(view))) + while (view.size && + isspace((unsigned char)CpuFeatures_StringView_Front(view))) view = CpuFeatures_StringView_PopFront(view, 1); - while (view.size && isspace(CpuFeatures_StringView_Back(view))) + while (view.size && + isspace((unsigned char)CpuFeatures_StringView_Back(view))) view = CpuFeatures_StringView_PopBack(view, 1); return view; } @@ -115,14 +118,16 @@ static int HexValue(const char c) { return -1; } -// Returns -1 if view contains non digits. +// Returns -1 if view contains non digits, is empty, or overflows. static int ParsePositiveNumberWithBase(const StringView view, int base) { + if (view.size == 0) return -1; int result = 0; StringView remainder = view; for (; remainder.size; remainder = CpuFeatures_StringView_PopFront(remainder, 1)) { const int value = HexValue(CpuFeatures_StringView_Front(remainder)); if (value < 0 || value >= base) return -1; + if (result > (INT_MAX - value) / base) return -1; result = (result * base) + value; } return result; diff --git a/test/string_view_test.cc b/test/string_view_test.cc index 3af70c70..4e33de1f 100644 --- a/test/string_view_test.cc +++ b/test/string_view_test.cc @@ -124,19 +124,37 @@ TEST(StringViewTest, CpuFeatures_StringView_TrimWhitespace) { str("first middle last")); EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last")), str("first middle last")); + EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("")), str("")); + EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" ")), str("")); + // Ensure non-ASCII characters (with high bit set) do not cause undefined behavior in isspace(). + EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" \xff abc \x80 ")), + str("\xff abc \x80")); } TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber) { EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("42")), 42); + EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0")), 0); + EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x0")), 0); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a")), 42); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A")), 42); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A2a")), 10794); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a2A")), 10794); + EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x")), -1); + EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x ")), -1); + EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0xG")), -1); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-10")), -1); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-0x2A")), -1); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("abc")), -1); EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("")), -1); + + // Overflow handling + EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber( + str("999999999999999999999999999999")), + -1); + EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber( + str("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")), + -1); } TEST(StringViewTest, CpuFeatures_StringView_CopyString) {