From eab266faa93175b33b06d6ada9ff998ef5de0824 Mon Sep 17 00:00:00 2001 From: Firat Hajiyev Date: Sun, 18 Oct 2026 18:14:42 -0400 Subject: [PATCH] Handle String::toInt overflow --- api/String.cpp | 29 ++++++++++++++++++++++++-- test/src/String/test_toInt.cpp | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/api/String.cpp b/api/String.cpp index 4f176374..be8fd748 100644 --- a/api/String.cpp +++ b/api/String.cpp @@ -25,6 +25,7 @@ #include "deprecated-avr-comp/avr/dtostrf.h" #include +#include namespace arduino { @@ -732,8 +733,32 @@ void String::trim(void) long String::toInt(void) const { - if (buffer) return atol(buffer); - return 0; + if (!buffer) return 0; + + char const *p = buffer; + while (isspace(static_cast(*p))) p++; + + bool const negative = *p == '-'; + if (negative || *p == '+') p++; + + unsigned long value = 0; + unsigned long const negative_limit = static_cast(-(LONG_MIN + 1L)) + 1UL; + unsigned long const limit = negative + ? negative_limit + : static_cast(LONG_MAX); + unsigned long const cutoff = limit / 10UL; + unsigned long const cutlim = limit % 10UL; + + while (isdigit(static_cast(*p))) { + unsigned long const digit = static_cast(*p - '0'); + if (value > cutoff || (value == cutoff && digit > cutlim)) return 0; + value = value * 10UL + digit; + p++; + } + + if (!negative) return static_cast(value); + if (value == negative_limit) return LONG_MIN; + return -static_cast(value); } float String::toFloat(void) const diff --git a/test/src/String/test_toInt.cpp b/test/src/String/test_toInt.cpp index c93fcc4a..40d13bc1 100644 --- a/test/src/String/test_toInt.cpp +++ b/test/src/String/test_toInt.cpp @@ -10,6 +10,9 @@ #include +#include +#include + #include #include "StringPrinter.h" @@ -45,3 +48,37 @@ TEST_CASE ("Testing String::toInt when string does not have a buffer", "[String- arduino::String str(buffer); REQUIRE(str.toInt() == 0); } + +TEST_CASE ("Testing String::toInt when string exceeds the long range", "[String-toInt-05]") +{ + unsigned long const minimum_magnitude = static_cast(-(LONG_MIN + 1L)) + 1UL; + std::string const one_past_maximum = std::to_string(static_cast(LONG_MAX) + 1UL); + std::string const one_past_minimum = "-" + std::to_string(minimum_magnitude + 1UL); + arduino::String positive_boundary(one_past_maximum.c_str()); + arduino::String negative_boundary(one_past_minimum.c_str()); + arduino::String positive("999999999999999999999999999999999999"); + arduino::String negative("-999999999999999999999999999999999999"); + + REQUIRE(positive_boundary.toInt() == 0); + REQUIRE(negative_boundary.toInt() == 0); + REQUIRE(positive.toInt() == 0); + REQUIRE(negative.toInt() == 0); +} + +TEST_CASE ("Testing String::toInt at the long range limits", "[String-toInt-06]") +{ + arduino::String maximum(std::to_string(LONG_MAX).c_str()); + arduino::String minimum(std::to_string(LONG_MIN).c_str()); + + REQUIRE(maximum.toInt() == LONG_MAX); + REQUIRE(minimum.toInt() == LONG_MIN); +} + +TEST_CASE ("Testing String::toInt keeps atol parsing behavior", "[String-toInt-07]") +{ + arduino::String negative(" \t-123abc"); + arduino::String positive("+456xyz"); + + REQUIRE(negative.toInt() == -123); + REQUIRE(positive.toInt() == 456); +}