Skip to content

Commit 6aee1f9

Browse files
authored
[libc][math][c23] Fix bounds checking and add FE_INVALID raising in {,u}fromfp{,x}* (#86892)
See #86692 (comment) and #86892 (comment). cc @lntue @nickdesaulniers
1 parent 8dcff10 commit 6aee1f9

File tree

5 files changed

+975
-481
lines changed

5 files changed

+975
-481
lines changed

libc/src/__support/FPUtil/NearestIntegerOperations.h

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,27 +247,69 @@ round_using_current_rounding_mode(T x) {
247247
template <bool IsSigned, typename T>
248248
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T>
249249
fromfp(T x, int rnd, unsigned int width) {
250-
if (width == 0U)
250+
using StorageType = typename FPBits<T>::StorageType;
251+
252+
constexpr StorageType EXPLICIT_BIT =
253+
FPBits<T>::SIG_MASK - FPBits<T>::FRACTION_MASK;
254+
255+
if (width == 0U) {
256+
raise_except_if_required(FE_INVALID);
257+
return FPBits<T>::quiet_nan().get_val();
258+
}
259+
260+
FPBits<T> bits(x);
261+
262+
if (bits.is_inf_or_nan()) {
263+
raise_except_if_required(FE_INVALID);
251264
return FPBits<T>::quiet_nan().get_val();
265+
}
252266

253267
T rounded_value = round_using_specific_rounding_mode(x, rnd);
254268

255269
if constexpr (IsSigned) {
256270
// T can't hold a finite number >= 2.0 * 2^EXP_BIAS.
257271
if (width - 1 > FPBits<T>::EXP_BIAS)
258272
return rounded_value;
259-
if (rounded_value < -T(1U << (width - 1U)))
273+
274+
StorageType range_exp = width - 1U + FPBits<T>::EXP_BIAS;
275+
// rounded_value < -2^(width - 1)
276+
T range_min =
277+
FPBits<T>::create_value(Sign::NEG, range_exp, EXPLICIT_BIT).get_val();
278+
if (rounded_value < range_min) {
279+
raise_except_if_required(FE_INVALID);
260280
return FPBits<T>::quiet_nan().get_val();
261-
if (rounded_value > T((1U << (width - 1U)) - 1U))
281+
}
282+
// rounded_value > 2^(width - 1) - 1
283+
T range_max =
284+
FPBits<T>::create_value(Sign::POS, range_exp, EXPLICIT_BIT).get_val() -
285+
T(1.0);
286+
if (rounded_value > range_max) {
287+
raise_except_if_required(FE_INVALID);
262288
return FPBits<T>::quiet_nan().get_val();
289+
}
290+
263291
return rounded_value;
264292
}
265293

266-
if (rounded_value < T(0.0))
294+
if (rounded_value < T(0.0)) {
295+
raise_except_if_required(FE_INVALID);
267296
return FPBits<T>::quiet_nan().get_val();
297+
}
298+
268299
// T can't hold a finite number >= 2.0 * 2^EXP_BIAS.
269-
if (width <= FPBits<T>::EXP_BIAS && rounded_value > T(1U << width) - 1U)
300+
if (width > FPBits<T>::EXP_BIAS)
301+
return rounded_value;
302+
303+
StorageType range_exp = width + FPBits<T>::EXP_BIAS;
304+
// rounded_value > 2^width - 1
305+
T range_max =
306+
FPBits<T>::create_value(Sign::POS, range_exp, EXPLICIT_BIT).get_val() -
307+
T(1.0);
308+
if (rounded_value > range_max) {
309+
raise_except_if_required(FE_INVALID);
270310
return FPBits<T>::quiet_nan().get_val();
311+
}
312+
271313
return rounded_value;
272314
}
273315

0 commit comments

Comments
 (0)