[libc-commits] [libc] [libc] Fixing float128 UB error (PR #211593)
via libc-commits
libc-commits at lists.llvm.org
Thu Jul 30 08:24:18 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Zorojuro (Sukumarsawant)
<details>
<summary>Changes</summary>
DRAFT( to be updated )
---
Full diff: https://github.com/llvm/llvm-project/pull/211593.diff
4 Files Affected:
- (modified) libc/src/__support/FPUtil/CMakeLists.txt (+1)
- (modified) libc/src/__support/FPUtil/dyadic_float.h (+6-1)
- (modified) libc/src/__support/FPUtil/float128.h (+19-2)
- (modified) libc/test/src/__support/FPUtil/float128_test.cpp (+36-3)
``````````diff
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 8b6ac8027b52d..ab423a2622e5f 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -310,6 +310,7 @@ add_header_library(
libc.src.__support.macros.attributes
libc.src.__support.macros.config
libc.src.__support.uint128
+ libc.src.__support.CPP.limits
)
add_subdirectory(generic)
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index c218632131934..4d32724f51b2c 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -472,7 +472,12 @@ template <size_t Bits> struct DyadicFloat {
// exponents coming in to this function _shouldn't_ be that large). The
// result should always end up as a positive size_t.
size_t shift = -static_cast<size_t>(exponent);
- new_mant >>= shift;
+ size_t limit =
+ static_cast<size_t>(cpp::numeric_limits<MantissaType>::digits);
+ if (shift >= limit)
+ new_mant = 0;
+ else
+ new_mant >>= shift;
}
if (sign.is_neg()) {
diff --git a/libc/src/__support/FPUtil/float128.h b/libc/src/__support/FPUtil/float128.h
index b1bcafefd61a4..e7db3594b4e9e 100644
--- a/libc/src/__support/FPUtil/float128.h
+++ b/libc/src/__support/FPUtil/float128.h
@@ -10,6 +10,7 @@
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT128_H
#include "hdr/stdint_proxy.h"
+#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/comparison_operations.h"
@@ -69,13 +70,29 @@ struct Float128 {
template <typename T, cpp::enable_if_t<cpp::is_integral_v<T>, int> = 0>
LIBC_INLINE constexpr explicit operator T() const {
+ constexpr T MIN_T = cpp::numeric_limits<T>::min();
+ constexpr T MAX_T = cpp::numeric_limits<T>::max();
FPBits<Float128> x_bits(*this);
// Raise FE_INVALID for inf and NaN
if (x_bits.is_inf_or_nan()) {
raise_except_if_required(FE_INVALID);
+ return x_bits.is_neg() ? MIN_T : MAX_T;
}
- int x_bits_exp =
- x_bits.get_explicit_exponent() - FPBits<Float128>::FRACTION_LEN;
+ int exponent = x_bits.get_explicit_exponent();
+ constexpr int EXPONENT_LIMIT = cpp::is_signed_v<T>
+ ? static_cast<int>(sizeof(T) * 8) - 1
+ : static_cast<int>(sizeof(T) * 8);
+ if (exponent > EXPONENT_LIMIT) {
+ raise_except_if_required(FE_INVALID);
+ return x_bits.is_neg() ? MIN_T : MAX_T;
+ } else if (exponent == EXPONENT_LIMIT) {
+ if (x_bits.is_pos() || x_bits.get_mantissa() != 0) {
+ raise_except_if_required(FE_INVALID);
+ return x_bits.is_neg() ? MIN_T : MAX_T;
+ }
+ }
+
+ int x_bits_exp = exponent - FPBits<Float128>::FRACTION_LEN;
// sign * 2^(exp-bias) * mantissa
DyadicFloat<FPBits<Float128>::STORAGE_LEN> xd(
x_bits.sign(), x_bits_exp, x_bits.get_explicit_mantissa());
diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index b4ee0439ba0f5..a249e117a2d68 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -80,7 +80,8 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
ASSERT_EQ(static_cast<int>(Float128(-1.9)), -1);
ASSERT_EQ(static_cast<int>(Float128(1.9f)), 1);
- // Extreme values
+ // Border values
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
ASSERT_EQ(static_cast<int>(Float128(INT_MAX)), INT_MAX);
ASSERT_EQ(static_cast<int>(Float128(INT_MIN)), INT_MIN);
ASSERT_EQ(static_cast<long long>(Float128(LLONG_MAX)), LLONG_MAX);
@@ -90,12 +91,36 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
// FP exceptions
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
- ASSERT_EQ(static_cast<int>(FPBits::quiet_nan().get_val()), 0);
+ ASSERT_EQ(static_cast<int>(FPBits::quiet_nan().get_val()), INT_MAX);
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ ASSERT_EQ(static_cast<int>(FPBits::inf().get_val()), INT_MAX);
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+
+ // Extreme values
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ ASSERT_EQ(static_cast<int>(Float128(1e300)), INT_MAX);
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ ASSERT_EQ(static_cast<int>(Float128(-1e300)), INT_MIN);
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ ASSERT_EQ(static_cast<int>(FPBits::inf(Sign::NEG).get_val()), INT_MIN);
EXPECT_FP_EXCEPTION(FE_INVALID);
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
- ASSERT_EQ(static_cast<int>(FPBits::inf().get_val()), 0);
+ ASSERT_EQ(static_cast<int>(FPBits::inf(Sign::POS).get_val()), INT_MAX);
EXPECT_FP_EXCEPTION(FE_INVALID);
+
+ // Small values
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ ASSERT_EQ(static_cast<int>(Float128(1e-300)), 0);
+ ASSERT_EQ(static_cast<int>(Float128(-1e-300)), 0);
+ ASSERT_EQ(static_cast<int>(Float128(0.5)), 0);
+ ASSERT_EQ(static_cast<int>(Float128(-0.5)), 0);
}
TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
@@ -106,4 +131,12 @@ TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
ASSERT_TRUE(Float128(7U) == Float128(7.0f));
ASSERT_TRUE(Float128(-7LL) == Float128(-7.0));
ASSERT_TRUE(Float128(123456789LL) == Float128(123456789.0));
+
+ // 2147483648.0 or 2^31 is out of bound in signed and not in unsigned
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ ASSERT_EQ(static_cast<int>(Float128(2147483648.0)), INT_MAX);
+ EXPECT_FP_EXCEPTION(FE_INVALID);
+
+ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+ ASSERT_EQ(static_cast<unsigned>(Float128(2147483648.0)), 2147483648U);
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/211593
More information about the libc-commits
mailing list