From f3744bdf9a7d60ad06a059ed881ac08d1a44669b Mon Sep 17 00:00:00 2001 From: Mryange Date: Mon, 21 Sep 2026 17:43:40 +0800 Subject: [PATCH] [fix](function) Reject overflowing IPv6 uint128 strings ### What problem does this PR solve? Issue Number: N/A Problem Summary: IPv6 decimal strings beyond the uint128 range previously wrapped during digit-by-digit parsing, and empty strings were accepted as zero. Add explicit empty-input and overflow checks so invalid values are rejected and the nullable function can return NULL. ### Release note None ### Check List (For Author) - Test: Focused BE ASAN unit test FunctionIpTest.IPv6FromUInt128StringRejectsEmptyAndOverflow - Behavior changed: Yes (invalid empty and out-of-range values are rejected) - Does this need documentation: No --- be/src/core/value/ipv6_value.h | 15 ++++++++++++++- be/test/exprs/function/function_ip_test.cpp | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/be/src/core/value/ipv6_value.h b/be/src/core/value/ipv6_value.h index 394ea7aad143fd..3a354ba6346867 100644 --- a/be/src/core/value/ipv6_value.h +++ b/be/src/core/value/ipv6_value.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include #include @@ -43,12 +44,24 @@ class IPv6Value { bool from_string(const std::string& ipv6_str) { return from_string(_value, ipv6_str); } static bool from_uint128_string(IPv6& value, const char* ipv6_str, size_t len) { + if (len == 0) { + return false; + } + + constexpr IPv6 max_value = std::numeric_limits::max(); + constexpr IPv6 max_value_div_10 = max_value / 10; + constexpr IPv6 max_value_mod_10 = max_value % 10; value = 0; for (size_t i = 0; i < len; ++i) { if (ipv6_str[i] < '0' || ipv6_str[i] > '9') { return false; // illegal character for uint128 } - value = value * 10 + (ipv6_str[i] - '0'); + const auto digit = static_cast(ipv6_str[i] - '0'); + if (value > max_value_div_10 || + (value == max_value_div_10 && digit > max_value_mod_10)) { + return false; + } + value = value * 10 + digit; } return true; } diff --git a/be/test/exprs/function/function_ip_test.cpp b/be/test/exprs/function/function_ip_test.cpp index a3f1f431de0879..704344a801a9ad 100644 --- a/be/test/exprs/function/function_ip_test.cpp +++ b/be/test/exprs/function/function_ip_test.cpp @@ -80,6 +80,24 @@ TEST(FunctionIpTest, StringToNumRejectsEmbeddedNullTail) { check_function_all_arg_comb("inet6_aton", input_types, ipv6_null_data); } +TEST(FunctionIpTest, IPv6FromUInt128StringRejectsEmptyAndOverflow) { + const std::string max_uint128 = "340282366920938463463374607431768211455"; + IPv6 max_value = 0; + EXPECT_TRUE(IPv6Value::from_uint128_string(max_value, max_uint128.data(), max_uint128.size())); + EXPECT_EQ(max_value, static_cast(-1)); + + for (const auto& value : + {std::string("340282366920938463463374607431768211456"), + std::string("680564733841876926926749214863536422913"), std::string()}) { + IPv6 parsed = 0; + EXPECT_FALSE(IPv6Value::from_uint128_string(parsed, value.data(), value.size())); + } + + IPv6 parsed = 0; + EXPECT_TRUE(IPv6Value::from_uint128_string(parsed, "1", 1)); + EXPECT_EQ(parsed, static_cast(1)); +} + TEST(FunctionIpTest, StringToIPv6AcceptsLongIPv4Spellings) { std::string mapped_ipv4_zero(IPV6_BINARY_LENGTH, '\0'); mapped_ipv4_zero[10] = static_cast(0xff);