[libcxx-commits] [libcxx] [libcxxabi] [libc++] Add __checked_int and replace uses of the overflow builtins with it (PR #234585)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Oct 22 04:22:15 PDT 2026
https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/234585
None
>From 6faa93a2ffd7d851934abcada1d4fe5d120e1e01 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 22 Oct 2026 13:21:56 +0200
Subject: [PATCH] [libc++] Add __checked_int and replace uses of the overflow
builtins with it
---
libcxx/include/CMakeLists.txt | 1 +
.../include/__charconv/from_chars_integral.h | 5 +-
libcxx/include/__charconv/traits.h | 12 +-
libcxx/include/__locale_dir/num.h | 26 ++--
libcxx/include/__mdspan/layout_left.h | 8 +-
libcxx/include/__mdspan/layout_right.h | 8 +-
libcxx/include/__mdspan/layout_stride.h | 21 ++--
libcxx/include/__mdspan/mdspan.h | 8 +-
libcxx/include/__memory/shared_ptr.h | 17 +--
libcxx/include/__numeric/gcd_lcm.h | 8 +-
.../include/__numeric/saturation_arithmetic.h | 14 +--
libcxx/include/__utility/checked_int.h | 113 ++++++++++++++++++
libcxx/include/fstream | 5 +-
libcxx/include/module.modulemap.in | 1 +
libcxxabi/src/cxa_vector.cpp | 36 +-----
15 files changed, 184 insertions(+), 99 deletions(-)
create mode 100644 libcxx/include/__utility/checked_int.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index fcb66d5fe2f48a..b5d560fe4f3823 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -969,6 +969,7 @@ set(files
__utility/as_lvalue.h
__utility/assume.h
__utility/auto_cast.h
+ __utility/checked_int.h
__utility/cmp.h
__utility/constant_wrapper.h
__utility/convert_to_integral.h
diff --git a/libcxx/include/__charconv/from_chars_integral.h b/libcxx/include/__charconv/from_chars_integral.h
index 8fd0c0cb4011ec..5509499e0e8645 100644
--- a/libcxx/include/__charconv/from_chars_integral.h
+++ b/libcxx/include/__charconv/from_chars_integral.h
@@ -20,6 +20,7 @@
#include <__type_traits/is_signed.h>
#include <__type_traits/is_unsigned.h>
#include <__type_traits/make_unsigned.h>
+#include <__utility/checked_int.h>
#include <limits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -189,7 +190,9 @@ __from_chars_integral(const char* __first, const char* __last, _Tp& __value, int
if (__i < __digits - 1)
__x = __x * __b + __c.__val;
else {
- if (!__itoa::__mul_overflowed(__x, __b, __x))
+ auto __res = __checked_int<_Tp>(__x) * static_cast<unsigned char>(__b);
+ __x = __res.__value();
+ if (!__res.__overflowed())
++__p;
__y = __c.__val;
break;
diff --git a/libcxx/include/__charconv/traits.h b/libcxx/include/__charconv/traits.h
index ab7faacc0947d8..fa6776f5777011 100644
--- a/libcxx/include/__charconv/traits.h
+++ b/libcxx/include/__charconv/traits.h
@@ -15,9 +15,9 @@
#include <__charconv/tables.h>
#include <__charconv/to_chars_base_10.h>
#include <__config>
-#include <__memory/addressof.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_unsigned.h>
+#include <__utility/checked_int.h>
#include <cstdint>
#include <limits>
@@ -101,12 +101,6 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t<sizeof(_Tp) == sizeof(__u
};
#endif
-template <typename _Tp, typename _Up>
-bool _LIBCPP_CONSTEXPR_SINCE_CXX23 __mul_overflowed(_Tp __a, _Up __b, _Tp& __r) {
- static_assert(is_unsigned<_Tp>::value);
- return __builtin_mul_overflow(__a, static_cast<_Tp>(__b), std::addressof(__r));
-}
-
template <typename _Tp>
struct _LIBCPP_HIDDEN __traits : __traits_base<_Tp> {
static _LIBCPP_CONSTEXPR const int digits = numeric_limits<_Tp>::digits10 + 1;
@@ -125,7 +119,9 @@ struct _LIBCPP_HIDDEN __traits : __traits_base<_Tp> {
} while (__p != __ep && __i != 0);
__a = __inner_product(__cprod + __i + 1, __cprod + __j, __pow() + 1, __cprod[__i]);
- if (__itoa::__mul_overflowed(__cprod[__j], __pow()[__j - __i], __b))
+ auto __res = __checked_int<type>(__cprod[__j]) * __pow()[__j - __i];
+ __b = __res.__value();
+ if (__res.__overflowed())
--__p;
return __p;
}
diff --git a/libcxx/include/__locale_dir/num.h b/libcxx/include/__locale_dir/num.h
index 6774903aa00693..923cf074ea290f 100644
--- a/libcxx/include/__locale_dir/num.h
+++ b/libcxx/include/__locale_dir/num.h
@@ -26,6 +26,7 @@
#include <__memory/unique_ptr.h>
#include <__system_error/errc.h>
#include <__type_traits/is_signed.h>
+#include <__utility/checked_int.h>
#include <cerrno>
#include <ios>
#include <streambuf>
@@ -465,7 +466,7 @@ class num_get : public locale::facet, private __num_get<_CharT> {
using _Unsigned = __make_unsigned_t<_MaybeSigned>;
// Stage 1
- int __base = this->__get_base(__iob);
+ unsigned char __base = this->__get_base(__iob);
// Stages 2 & 3
// These are combined into a single step where we parse the characters and calculate the value in one go instead of
@@ -555,8 +556,7 @@ class num_get : public locale::facet, private __num_get<_CharT> {
}
// Calculate the actual number
- _Unsigned __val = 0;
- bool __overflowed = false;
+ __checked_int<_Unsigned> __val(0);
for (; __first != __last; ++__first) {
auto __c = *__first;
if (!__grouping.empty() && __c == __thousands_sep) {
@@ -574,9 +574,7 @@ class num_get : public locale::facet, private __num_get<_CharT> {
__offset -= 6;
if (__offset >= __base)
break;
- // __val = (__val * __base) + __offset
- __overflowed |= __builtin_mul_overflow(__val, __base, std::addressof(__val)) ||
- __builtin_add_overflow(__val, __offset, std::addressof(__val));
+ __val = (__val * __base) + static_cast<unsigned short>(__offset);
__parsed_num = true;
++__dc;
}
@@ -584,29 +582,29 @@ class num_get : public locale::facet, private __num_get<_CharT> {
if (!__parsed_num) {
__err |= ios_base::failbit;
__v = 0;
- } else if (__overflowed) {
+ } else if (__val.__overflowed()) {
__err |= ios_base::failbit;
__v = is_signed<_MaybeSigned>::value && __negate
? numeric_limits<_MaybeSigned>::min()
: numeric_limits<_MaybeSigned>::max();
- } else if (!__negate) {
- if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max())) {
+ } else if (auto __value = __val.__value(); !__negate) {
+ if (__value > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max())) {
__err |= ios_base::failbit;
__v = numeric_limits<_MaybeSigned>::max();
} else {
- __v = __val;
+ __v = __value;
}
} else if (is_signed<_MaybeSigned>::value) {
- if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {
+ if (__value > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {
__err |= ios_base::failbit;
__v = numeric_limits<_MaybeSigned>::min();
- } else if (__val == static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {
+ } else if (__value == static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) {
__v = numeric_limits<_MaybeSigned>::min();
} else {
- __v = -__val;
+ __v = -__value;
}
} else {
- __v = -__val;
+ __v = -__value;
}
if (__grouping.size() != 0 && __g_end - __g < __num_get_base::__num_get_buf_sz)
diff --git a/libcxx/include/__mdspan/layout_left.h b/libcxx/include/__mdspan/layout_left.h
index fb1b59555b254b..d8af7de392df80 100644
--- a/libcxx/include/__mdspan/layout_left.h
+++ b/libcxx/include/__mdspan/layout_left.h
@@ -21,11 +21,11 @@
#include <__config>
#include <__fwd/mdspan.h>
#include <__mdspan/extents.h>
-#include <__memory/addressof.h>
#include <__type_traits/common_type.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_convertible.h>
#include <__type_traits/is_nothrow_constructible.h>
+#include <__utility/checked_int.h>
#include <__utility/integer_sequence.h>
#include <array>
@@ -57,10 +57,10 @@ class layout_left::mapping {
if constexpr (extents_type::rank() == 0)
return true;
- index_type __prod = __ext.extent(0);
+ __checked_int<index_type> __prod(__ext.extent(0));
for (rank_type __r = 1; __r < extents_type::rank(); __r++) {
- bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod));
- if (__overflowed)
+ __prod *= __ext.extent(__r);
+ if (__prod.__overflowed())
return false;
}
return true;
diff --git a/libcxx/include/__mdspan/layout_right.h b/libcxx/include/__mdspan/layout_right.h
index 7cb828022ea8e0..d3b01f32f56576 100644
--- a/libcxx/include/__mdspan/layout_right.h
+++ b/libcxx/include/__mdspan/layout_right.h
@@ -22,11 +22,11 @@
#include <__cstddef/size_t.h>
#include <__fwd/mdspan.h>
#include <__mdspan/extents.h>
-#include <__memory/addressof.h>
#include <__type_traits/common_type.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_convertible.h>
#include <__type_traits/is_nothrow_constructible.h>
+#include <__utility/checked_int.h>
#include <__utility/integer_sequence.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -57,10 +57,10 @@ class layout_right::mapping {
if constexpr (extents_type::rank() == 0)
return true;
- index_type __prod = __ext.extent(0);
+ __checked_int __prod(__ext.extent(0));
for (rank_type __r = 1; __r < extents_type::rank(); __r++) {
- bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod));
- if (__overflowed)
+ __prod *= __ext.extent(__r);
+ if (__prod.__overflowed())
return false;
}
return true;
diff --git a/libcxx/include/__mdspan/layout_stride.h b/libcxx/include/__mdspan/layout_stride.h
index 5ee4672e0d1cfb..d7d61634e2a353 100644
--- a/libcxx/include/__mdspan/layout_stride.h
+++ b/libcxx/include/__mdspan/layout_stride.h
@@ -22,7 +22,6 @@
#include <__config>
#include <__fwd/mdspan.h>
#include <__mdspan/extents.h>
-#include <__memory/addressof.h>
#include <__type_traits/common_type.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_convertible.h>
@@ -30,6 +29,7 @@
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_same.h>
#include <__utility/as_const.h>
+#include <__utility/checked_int.h>
#include <__utility/integer_sequence.h>
#include <__utility/swap.h>
#include <array>
@@ -85,10 +85,10 @@ class layout_stride::mapping {
if constexpr (__rank_ == 0)
return true;
- index_type __prod = __ext.extent(0);
- for (rank_type __r = 1; __r < __rank_; __r++) {
- bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod));
- if (__overflowed)
+ __checked_int __prod(__ext.extent(0));
+ for (rank_type __r = 1; __r < extents_type::rank(); __r++) {
+ __prod *= __ext.extent(__r);
+ if (__prod.__overflowed())
return false;
}
return true;
@@ -110,14 +110,11 @@ class layout_stride::mapping {
}
if (__ext.extent(__r) == static_cast<index_type>(0))
return true;
- index_type __prod = (__ext.extent(__r) - 1);
- bool __overflowed_mul =
- __builtin_mul_overflow(__prod, static_cast<index_type>(__strides[__r]), std::addressof(__prod));
- if (__overflowed_mul)
- return false;
- bool __overflowed_add = __builtin_add_overflow(__size, __prod, std::addressof(__size));
- if (__overflowed_add)
+ __checked_int<index_type> __prod{__ext.extent(__r) - 1};
+ __prod = __prod * static_cast<index_type>(__strides[__r]) + __size;
+ if (__prod.__overflowed())
return false;
+ __size = __prod.__value();
}
return true;
}
diff --git a/libcxx/include/__mdspan/mdspan.h b/libcxx/include/__mdspan/mdspan.h
index 3b78f792770f06..eba908da6caa08 100644
--- a/libcxx/include/__mdspan/mdspan.h
+++ b/libcxx/include/__mdspan/mdspan.h
@@ -39,6 +39,7 @@
#include <__type_traits/remove_pointer.h>
#include <__type_traits/remove_reference.h>
#include <__utility/as_const.h>
+#include <__utility/checked_int.h>
#include <__utility/integer_sequence.h>
#include <array>
#include <span>
@@ -254,10 +255,9 @@ class mdspan {
// Could leave this as only checked in debug mode: semantically size() is never
// guaranteed to be related to any accessible range
_LIBCPP_ASSERT_UNCATEGORIZED(
- false == ([&]<size_t... _Idxs>(index_sequence<_Idxs...>) {
- size_type __prod = 1;
- return (__builtin_mul_overflow(__prod, extent(_Idxs), std::addressof(__prod)) || ... || false);
- }(make_index_sequence<rank()>())),
+ [&]<size_t... _Idxs>(index_sequence<_Idxs...>) {
+ return !(__checked_int(extent(_Idxs)) * ...).__overflowed();
+ }(make_index_sequence<rank()>()),
"mdspan: size() is not representable as size_type");
return [&]<size_t... _Idxs>(index_sequence<_Idxs...>) {
return ((static_cast<size_type>(__map_.extents().extent(_Idxs))) * ... * size_type(1));
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 0db58b37a6288b..549b9df9390daf 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -54,6 +54,7 @@
#include <__type_traits/remove_reference.h>
#include <__type_traits/type_identity.h>
#include <__type_traits/void_t.h>
+#include <__utility/checked_int.h>
#include <__utility/declval.h>
#include <__utility/exception_guard.h>
#include <__utility/forward.h>
@@ -748,20 +749,20 @@ struct __unbounded_array_control_block<_Tp[], _Alloc> : __shared_weak_count {
// When there's 0 elements, the control block alone is enough since it holds one element.
// Otherwise, we allocate one fewer element than requested because the control block already
// holds one.
- size_t __bytes = sizeof(__unbounded_array_control_block);
- if (__elements != 0) {
- if (__builtin_mul_overflow(__elements - 1, sizeof(_Tp), &__bytes) ||
- __builtin_add_overflow(__bytes, sizeof(__unbounded_array_control_block), &__bytes))
- std::__throw_bad_array_new_length();
- }
+ __checked_int<size_t> __bytes(sizeof(__unbounded_array_control_block));
+ if (__elements != 0)
+ __bytes = __checked_int<size_t>(__elements - 1) * sizeof(__unbounded_array_control_block) +
+ sizeof(__unbounded_array_control_block);
// We use the bitwise formula below to ensure that we allocate enough bytes for the whole
// allocation to be a multiple of _Tp's alignment. That formula is taken from [1].
//
// [1]: https://en.wikipedia.org/wiki/Data_structure_alignment#Computing_padding
- if (__builtin_add_overflow(__bytes, __align - 1, &__bytes))
+ __bytes += __align - 1;
+ if (__bytes.__overflowed())
std::__throw_bad_array_new_length();
- return __bytes & ~(__align - 1);
+
+ return __bytes.__value() & ~(__align - 1);
}
_LIBCPP_HIDE_FROM_ABI_VIRTUAL
diff --git a/libcxx/include/__numeric/gcd_lcm.h b/libcxx/include/__numeric/gcd_lcm.h
index 753b42621fcc1f..7f9a1595d852f8 100644
--- a/libcxx/include/__numeric/gcd_lcm.h
+++ b/libcxx/include/__numeric/gcd_lcm.h
@@ -20,6 +20,7 @@
#include <__type_traits/is_signed.h>
#include <__type_traits/make_unsigned.h>
#include <__type_traits/remove_cv.h>
+#include <__utility/checked_int.h>
#include <limits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -105,10 +106,9 @@ template <class _Tp, class _Up>
using _Rp = common_type_t<_Tp, _Up>;
_Rp __val1 = std::__abs_in_type<_Rp>(__m) / std::gcd(__m, __n);
_Rp __val2 = std::__abs_in_type<_Rp>(__n);
- _Rp __res;
- [[maybe_unused]] bool __overflow = __builtin_mul_overflow(__val1, __val2, std::addressof(__res));
- _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__overflow, "Overflow in lcm");
- return __res;
+ auto __res = __checked_int(__val1) * __val2;
+ _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__res.__overflowed(), "Overflow in lcm");
+ return __res.__value();
}
#endif // _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/__numeric/saturation_arithmetic.h b/libcxx/include/__numeric/saturation_arithmetic.h
index f113370c271d01..2426e96f622fc8 100644
--- a/libcxx/include/__numeric/saturation_arithmetic.h
+++ b/libcxx/include/__numeric/saturation_arithmetic.h
@@ -12,8 +12,8 @@
#include <__assert>
#include <__config>
-#include <__memory/addressof.h>
#include <__type_traits/integer_traits.h>
+#include <__utility/checked_int.h>
#include <__utility/cmp.h>
#include <limits>
@@ -32,8 +32,8 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp __saturating_add(_Tp __x, _Tp __y) _
# if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101
return __builtin_elementwise_add_sat(__x, __y);
# else
- if (_Tp __sum; !__builtin_add_overflow(__x, __y, std::addressof(__sum)))
- return __sum;
+ if (auto __sum = __checked_int<_Tp>(__x) + __y; !__sum.__overflowed())
+ return __sum.__value();
// Handle overflow
if _LIBCPP_CONSTEXPR (__is_unsigned_integer_v<_Tp>) {
return std::numeric_limits<_Tp>::max();
@@ -56,8 +56,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __saturating_sub(_Tp __x, _Tp __y) noexcept
# if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101
return __builtin_elementwise_sub_sat(__x, __y);
# else
- if (_Tp __sub; !__builtin_sub_overflow(__x, __y, std::addressof(__sub)))
- return __sub;
+ if (auto __sub = __checked_int(__x) - __y; !__sub.__overflowed())
+ return __sub.__value();
// Handle overflow
if constexpr (__unsigned_integer<_Tp>) {
// Overflows if (x < y)
@@ -76,8 +76,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __saturating_sub(_Tp __x, _Tp __y) noexcept
template <__signed_or_unsigned_integer _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp __saturating_mul(_Tp __x, _Tp __y) noexcept {
- if (_Tp __mul; !__builtin_mul_overflow(__x, __y, std::addressof(__mul)))
- return __mul;
+ if (auto __mul = __checked_int(__x) * __y; !__mul.__overflowed())
+ return __mul.__value();
// Handle overflow
if constexpr (__unsigned_integer<_Tp>) {
return std::numeric_limits<_Tp>::max();
diff --git a/libcxx/include/__utility/checked_int.h b/libcxx/include/__utility/checked_int.h
new file mode 100644
index 00000000000000..724585bc7da02e
--- /dev/null
+++ b/libcxx/include/__utility/checked_int.h
@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_CHECKED_INT_H
+#define _LIBCPP___UTILITY_CHECKED_INT_H
+
+#include <__config>
+#include <__memory/addressof.h>
+#include <__type_traits/enable_if.h>
+#include <__type_traits/is_signed.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _From, class _To>
+inline const bool __is_lossless_conversion_v =
+ is_signed<_From>::value == is_signed<_To>::value
+ ? sizeof(_From) <= sizeof(_To)
+ : is_signed<_To>::value && sizeof(_From) < sizeof(_To);
+
+template <class _IntT>
+class __checked_int {
+ _IntT __value_ = 0;
+ bool __overflowed_ = false;
+
+ __checked_int() = default;
+
+public:
+ _LIBCPP_CONSTEXPR explicit __checked_int(_IntT __value) : __value_(__value) {}
+
+ _LIBCPP_CONSTEXPR _IntT __value() const { return __value_; }
+ _LIBCPP_CONSTEXPR bool __overflowed() const { return __overflowed_; }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int& operator+=(__checked_int& __lhs, __checked_int __rhs) {
+ __lhs.__overflowed_ |=
+ __rhs.__overflowed_ | __builtin_add_overflow(__lhs.__value_, __rhs.__value_, std::addressof(__lhs.__value_));
+ return __lhs;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int& operator-=(__checked_int& __lhs, __checked_int __rhs) {
+ __lhs.__overflowed_ |=
+ __rhs.__overflowed_ | __builtin_sub_overflow(__lhs.__value_, __rhs.__value_, std::addressof(__lhs.__value_));
+ return __lhs;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int& operator*=(__checked_int& __lhs, __checked_int __rhs) {
+ __lhs.__overflowed_ |=
+ __rhs.__overflowed_ | __builtin_mul_overflow(__lhs.__value_, __rhs.__value_, std::addressof(__lhs.__value_));
+ return __lhs;
+ }
+
+ template <class _OtherInt, __enable_if_t<__is_lossless_conversion_v<_OtherInt, _IntT>, int> = 0>
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int& operator+=(__checked_int& __lhs, _OtherInt __rhs) {
+ return __lhs += __checked_int(__rhs);
+ }
+
+ template <class _OtherInt, __enable_if_t<__is_lossless_conversion_v<_OtherInt, _IntT>, int> = 0>
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int& operator-=(__checked_int& __lhs, _OtherInt __rhs) {
+ return __lhs -= __checked_int(__rhs);
+ }
+
+ template <class _OtherInt, __enable_if_t<__is_lossless_conversion_v<_OtherInt, _IntT>, int> = 0>
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int& operator*=(__checked_int& __lhs, _OtherInt __rhs) {
+ return __lhs *= __checked_int(__rhs);
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int operator+(__checked_int __lhs, __checked_int __rhs) {
+ auto __copy = __lhs;
+ __copy += __rhs;
+ return __copy;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int operator-(__checked_int __lhs, __checked_int __rhs) {
+ auto __copy = __lhs;
+ __copy -= __rhs;
+ return __copy;
+ }
+
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int operator*(__checked_int __lhs, __checked_int __rhs) {
+ auto __copy = __lhs;
+ __copy *= __rhs;
+ return __copy;
+ }
+
+ template <class _OtherInt, __enable_if_t<__is_lossless_conversion_v<_OtherInt, _IntT>, int> = 0>
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int operator+(__checked_int __lhs, _OtherInt __rhs) {
+ return __lhs + __checked_int(__rhs);
+ }
+
+ template <class _OtherInt, __enable_if_t<__is_lossless_conversion_v<_OtherInt, _IntT>, int> = 0>
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int operator-(__checked_int __lhs, _OtherInt __rhs) {
+ return __lhs - __checked_int(__rhs);
+ }
+
+ template <class _OtherInt, __enable_if_t<__is_lossless_conversion_v<_OtherInt, _IntT>, int> = 0>
+ _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __checked_int operator*(__checked_int __lhs, _OtherInt __rhs) {
+ return __lhs * __checked_int(__rhs);
+ }
+};
+
+_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__checked_int);
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___UTILITY_CHECKED_INT_H
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 749abe971594a9..ca922f2e8094b7 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -204,6 +204,7 @@ typedef basic_fstream<wchar_t> wfstream;
# include <__ostream/basic_ostream.h>
# include <__type_traits/enable_if.h>
# include <__type_traits/is_same.h>
+# include <__utility/checked_int.h>
# include <__utility/move.h>
# include <__utility/swap.h>
# include <__utility/unreachable.h>
@@ -546,8 +547,8 @@ private:
} else {
// Otherwise seek to the requested position in the underlying C stream and drop the buffer. This is the expensive
// path, since it performs a syscall.
- if (off_type __offset; __builtin_sub_overflow(__byte_off, this->egptr() - this->gptr(), &__offset) ||
- __fseek(__file_, __offset, SEEK_CUR))
+ if (auto __offset = __checked_int<off_type>(__byte_off) - (this->egptr() - this->gptr());
+ __offset.__overflowed() || __fseek(__file_, __offset.__value(), SEEK_CUR))
return pos_type(off_type(-1));
this->setg(nullptr, nullptr, nullptr);
__cm_ = 0;
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 6ca65ba556fa1c..2f6fb0177820d9 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2263,6 +2263,7 @@ module std {
export std_core.type_traits.decay // the macro expansion uses that trait
}
module cmp { header "__utility/cmp.h" }
+ module checked_int { header "__utility/checked_int.h" }
module constant_wrapper { header "__utility/constant_wrapper.h" }
module convert_to_integral { header "__utility/convert_to_integral.h" }
module default_three_way_comparator { header "__utility/default_three_way_comparator.h" }
diff --git a/libcxxabi/src/cxa_vector.cpp b/libcxxabi/src/cxa_vector.cpp
index 5eac7a8dc97294..156c8654bffe2c 100644
--- a/libcxxabi/src/cxa_vector.cpp
+++ b/libcxxabi/src/cxa_vector.cpp
@@ -15,6 +15,7 @@
#include <exception> // for std::terminate
#include <new> // for std::bad_array_new_length
+#include <__utility/checked_int.h>
#include "abort_message.h"
@@ -124,38 +125,11 @@ namespace {
#endif
}
-bool mul_overflow(size_t x, size_t y, size_t *res) {
-#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_mul_overflow)) \
- || defined(_LIBCXXABI_COMPILER_GCC)
- return __builtin_mul_overflow(x, y, res);
-#else
- *res = x * y;
- return x && ((*res / x) != y);
-#endif
-}
-
-bool add_overflow(size_t x, size_t y, size_t *res) {
-#if (defined(_LIBCXXABI_COMPILER_CLANG) && __has_builtin(__builtin_add_overflow)) \
- || defined(_LIBCXXABI_COMPILER_GCC)
- return __builtin_add_overflow(x, y, res);
-#else
- *res = x + y;
- return *res < y;
-#endif
-}
-
-size_t calculate_allocation_size_or_throw(size_t element_count,
- size_t element_size,
- size_t padding_size) {
- size_t element_heap_size;
- if (mul_overflow(element_count, element_size, &element_heap_size))
+size_t calculate_allocation_size_or_throw(size_t element_count, size_t element_size, size_t padding_size) {
+ auto size = std::__checked_int<size_t>(element_count) * element_size + padding_size;
+ if (size.__overflowed())
throw_bad_array_new_length();
-
- size_t allocation_size;
- if (add_overflow(element_heap_size, padding_size, &allocation_size))
- throw_bad_array_new_length();
-
- return allocation_size;
+ return size.__value();
}
} // namespace
More information about the libcxx-commits
mailing list