[libcxx-commits] [libcxx] [libc++] Suppress unsigned-integer-overflow warning in <charconv> (PR #225801)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Sep 29 09:53:45 PDT 2026
https://github.com/hchataing updated https://github.com/llvm/llvm-project/pull/225801
>From a81bd590624cdde6dcfe6e5666324c1ca196a591 Mon Sep 17 00:00:00 2001
From: Henri Chataing <henrichataing at google.com>
Date: Wed, 23 Sep 2026 14:51:23 +0000
Subject: [PATCH] [libc++] Suppress unsigned-integer-overflow warning in
<charconv>
Invoking __complement with 0 as parameter triggers this runtime error:
> include/c++/v1/__charconv/traits.h:181:19: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'unsigned long'
> SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior include/c++/v1/__charconv/traits.h:181:19
---
libcxx/include/__charconv/traits.h | 3 ++-
.../charconv/charconv.from.chars/integral.pass.cpp | 12 ++++++++++++
libcxx/test/support/charconv_test_helpers.h | 4 +++-
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__charconv/traits.h b/libcxx/include/__charconv/traits.h
index b8c840d1ebe32..2f08dac4c2afe 100644
--- a/libcxx/include/__charconv/traits.h
+++ b/libcxx/include/__charconv/traits.h
@@ -155,7 +155,8 @@ struct _LIBCPP_HIDDEN __traits : __traits_base<_Tp> {
} // namespace __itoa
template <typename _Tp>
-inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _Tp __complement(_Tp __x) {
+inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK _Tp __complement(_Tp __x) {
static_assert(is_unsigned<_Tp>::value, "cast to unsigned first");
return _Tp(~__x + 1);
}
diff --git a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp
index 4708da4c38b9b..1947116429d1f 100644
--- a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp
+++ b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp
@@ -8,6 +8,9 @@
// UNSUPPORTED: c++03, c++11, c++14
+// FIXME: Enable this for all tests once possible
+// ADDITIONAL_COMPILE_FLAGS(ubsan): -fsanitize=unsigned-integer-overflow
+
// <charconv>
// constexpr from_chars_result from_chars(const char* first, const char* last,
@@ -134,6 +137,15 @@ struct test_signed
// the member ec is equal to errc::invalid_argument.
assert(r.ec == std::errc::invalid_argument);
}
+
+ {
+ // Ensure "-0" does not trigger unsigned integer overflow.
+ char s[] = "-0";
+ r = std::from_chars(s, s + sizeof(s), x);
+ assert(r.ec == std::errc{});
+ assert(r.ptr == s + 2);
+ assert(x == 0);
+ }
}
};
diff --git a/libcxx/test/support/charconv_test_helpers.h b/libcxx/test/support/charconv_test_helpers.h
index fcae09478457b..fce7db24cc286 100644
--- a/libcxx/test/support/charconv_test_helpers.h
+++ b/libcxx/test/support/charconv_test_helpers.h
@@ -323,7 +323,9 @@ template <template <typename> class Fn, typename... Ts>
TEST_CONSTEXPR_CXX23 void
run(type_list<Ts...>)
{
- int ls[sizeof...(Ts)] = {(Fn<Ts>{}(), 0)...};
+ // Avoid constant-folding the array initializer at compile time when Fn<Ts>{}() is constexpr.
+ int dummy = 0;
+ int ls[sizeof...(Ts)] = {(Fn<Ts>{}(), dummy)...};
(void)ls;
}
More information about the libcxx-commits
mailing list