From 8d6a722ed8252ceb56e3764d02c8b625062fc30f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 30 Oct 2023 23:56:53 +0100 Subject: [PATCH] Fix C++17 implementation of wxString::ToCULong() Do use std::from_chars() in it as otherwise values greater than LONG_MAX failed to parse. Handle negative numbers explicitly to still parse them in this function as well, as needs to be done for compatibility. Add a test case for the previously failing numbers. Closes #23957. --- src/common/string.cpp | 32 +++++++++++++++++++++++--------- tests/strings/strings.cpp | 11 +++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/common/string.cpp b/src/common/string.cpp index c769245f57..bcd78b67bd 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -1633,20 +1633,34 @@ bool wxString::ToCLong(long *pVal, int base) const bool wxString::ToCULong(unsigned long *pVal, int base) const { - // We intentionally don't use std::from_chars() here because this function - // is supposed to be compatible with strtoul() and so _succeed_ for "-1", - // for example, instead of returning an error as from_chars() (much more - // logically) does. - wxCHECK_MSG( pVal, false, "null output pointer" ); - long l; - if ( !ToCLong(&l, base) ) + const wxScopedCharBuffer& buf = utf8_str(); + auto start = buf.data(); + const auto end = start + buf.length(); + + if ( !SetBaseAndSkipPrefix(base, start, end) ) return false; - *pVal = static_cast(l); + // Extra complication: for compatibility reasons, this function does accept + // "-1" as valid input (as strtoul() does!), but from_chars() doesn't, for + // unsigned values, so check for this separately. + if ( *start == '-' ) + { + long l; + const auto res = std::from_chars(start, end, l, base); - return true; + if ( res.ec != std::errc{} || res.ptr != end ) + return false; + + *pVal = static_cast(l); + + return true; + } + + const auto res = std::from_chars(start, end, *pVal, base); + + return res.ec == std::errc{} && res.ptr == end; } bool wxString::ToCDouble(double *pVal) const diff --git a/tests/strings/strings.cpp b/tests/strings/strings.cpp index 30e6082406..43afe86eba 100644 --- a/tests/strings/strings.cpp +++ b/tests/strings/strings.cpp @@ -607,6 +607,17 @@ static const struct ToLongData { wxT("0x11"), 17, Number_Ok, 0 }, { wxT("0x11"), 0, Number_Invalid, 8 }, { wxT("0x11"), 17, Number_Ok, 16 }, + + { +#if SIZEOF_LONG == 4 + wxT("0xffffffff"), +#elif SIZEOF_LONG == 8 + wxT("0xffffffffffffffff"), +#else + #error "Unknown sizeof(long)" +#endif + (TestValue_t)ULONG_MAX, Number_Unsigned, 0 + }, }; wxGCC_WARNING_RESTORE(missing-field-initializers)