Skip to content

Commit 392b603

Browse files
committed
Fix porting mistake found by fuzzing: X87DoubleExtendedS::from_bits was clearing the significand's MSB.
1 parent 8270711 commit 392b603

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

src/ieee.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ pub trait Semantics: Sized {
8282
const QNAN_BIT: usize = Self::PRECISION - 2;
8383

8484
/// The significand bitpattern to mark a NaN as quiet.
85-
/// NOTE: for X87DoubleExtended we need to set two bits instead of 2.
85+
/// NOTE: for X87DoubleExtended we need to set two bits instead of 1.
8686
const QNAN_SIGNIFICAND: Limb = 1 << Self::QNAN_BIT;
8787

8888
fn from_bits(bits: u128) -> IeeeFloat<Self> {
@@ -206,7 +206,7 @@ impl Semantics for X87DoubleExtendedS {
206206
let sign = bits & (1 << (Self::BITS - 1));
207207
let exponent = (bits & !sign) >> Self::PRECISION;
208208
let mut r = IeeeFloat {
209-
sig: [bits & ((1 << (Self::PRECISION - 1)) - 1)],
209+
sig: [bits & ((1 << Self::PRECISION) - 1)],
210210
// Convert the exponent from its bias representation to a signed integer.
211211
exp: (exponent as ExpInt) - Self::MAX_EXP,
212212
category: Category::Zero,

tests/downstream.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Tests added to `rustc_apfloat`, that were not ported from the C++ code.
22
3-
use rustc_apfloat::ieee::{Double, Single};
3+
use rustc_apfloat::ieee::{Double, Single, X87DoubleExtended};
44
use rustc_apfloat::Float;
55

66
// `f32 -> i128 -> f32` previously-crashing bit-patterns (found by fuzzing).
@@ -385,3 +385,29 @@ fn fuzz_fma_with_expected_outputs() {
385385
assert_eq!(a.mul_add(b, c).value.to_bits(), expected_bits.into());
386386
}
387387
}
388+
389+
// x87 80-bit "extended precision"/`long double` bit-patterns which used to
390+
// produce the wrong output when negated (found by fuzzing - though fuzzing also
391+
// found many examples in all ops, as the root issue was the handling of the
392+
// bit-level encoding itself, but negation was the easiest op to test here).
393+
pub const FUZZ_X87_F80_NEG_CASES_WITH_EXPECTED_OUTPUTS: &[(u128, u128)] = &[
394+
(
395+
0x01010101010100000000, /* 3.05337213397376214408E-4857 */
396+
0x81010101010100000000, /* -3.05337213397376214408E-4857 */
397+
),
398+
(
399+
0x0000ff7f2300ff000000, /* 6.71098449692300485303E-4932 */
400+
0x8001ff7f2300ff000000, /* -6.71098449692300485303E-4932 */
401+
),
402+
(
403+
0x00008000000000000000, /* 3.36210314311209350626E-4932 */
404+
0x80018000000000000000, /* -3.36210314311209350626E-4932 */
405+
),
406+
];
407+
408+
#[test]
409+
fn fuzz_x87_f80_neg_with_expected_outputs() {
410+
for &(bits, expected_bits) in FUZZ_X87_F80_NEG_CASES_WITH_EXPECTED_OUTPUTS {
411+
assert_eq!((-X87DoubleExtended::from_bits(bits)).to_bits(), expected_bits);
412+
}
413+
}

0 commit comments

Comments
 (0)