Skip to content

Commit

Permalink
Fix porting mistake found by fuzzing: `mul_add(finite, finite, ±inf_o…
Browse files Browse the repository at this point in the history
…r_nan)` needs to ignore the finite multiplication.
  • Loading branch information
eddyb committed Jul 12, 2023
1 parent dbb239d commit 8270711
Show file tree
Hide file tree
Showing 2 changed files with 355 additions and 1 deletion.
13 changes: 12 additions & 1 deletion src/ieee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,18 @@ impl<S: Semantics> Float for IeeeFloat<S> {
// extended-precision calculation.
if !self.is_finite_non_zero() || !multiplicand.is_finite_non_zero() || !addend.is_finite() {
let mut status;
self = unpack!(status=, self.mul_r(multiplicand, round));
if self.is_finite_non_zero() && multiplicand.is_finite_non_zero() {
// HACK(eddyb) this corresponds to the case where the C++ code
// (`multiplySpecials`) is effectively a noop: no multiplication
// is actually performed, because we're really only here to handle
// the "infinite/NaN `addend`" special-case, which needs to ignore
// the "finite * finite" multiplication entirely, instead of letting
// it e.g. overflow into infinity (and trample over `addend`).
assert!(!addend.is_finite());
status = Status::OK;
} else {
self = unpack!(status=, self.mul_r(multiplicand, round));
}

// FS can only be Status::OK or Status::INVALID_OP. There is no more work
// to do in the latter case. The IEEE-754R standard says it is
Expand Down
343 changes: 343 additions & 0 deletions tests/downstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,346 @@ fn fuzz_roundtrip_through_i128() {
);
}
}

// `f32` FMA bit-patterns which used to produce the wrong output (found by fuzzing).
pub const FUZZ_IEEE32_FMA_CASES_WITH_EXPECTED_OUTPUTS: &[((u32, u32, u32), u32)] = &[
((0x00001000 /* 5.74e-42 */, 0x0000001a /* 3.6e-44 */, 0xffff1a00 /* NaN */), 0xffff1a00 /* NaN */),
((0x000080aa /* 4.6156e-41 */, 0xaaff0000 /* -4.52971e-13 */, 0xff9e007f /* NaN */), 0xff9e007f /* NaN */),
((0x0000843f /* 4.7441e-41 */, 0x0084ff80 /* 1.2213942e-38 */, 0xffff8000 /* NaN */), 0xffff8000 /* NaN */),
((0x00009eaa /* 5.6918e-41 */, 0x201d7f1e /* 1.3340477e-19 */, 0xffff0001 /* NaN */), 0xffff0001 /* NaN */),
((0x020400ff /* 9.698114e-38 */, 0x7f7f2200 /* 3.3912968e+38 */, 0xffffffff /* NaN */), 0xffffffff /* NaN */),
((0x02060320 /* 9.845662e-38 */, 0x20002521 /* 1.0854307e-19 */, 0x7f800000 /* inf */), 0x7f800000 /* inf */),
(
(0x04000080 /* 1.5046557e-36 */, 0xff7fff00 /* -3.4027717e+38 */, 0xff800000 /* -inf */),
0xff800000, /* -inf */
),
(
(0x04007faa /* 1.5104948e-36 */, 0xff200000 /* -2.1267648e+38 */, 0xffff0000 /* NaN */),
0xffff0000, /* NaN */
),
((0x1e0603ff /* 7.094727e-21 */, 0x00100000 /* 1.469368e-39 */, 0xffffff4f /* NaN */), 0xffffff4f /* NaN */),
((0x200004aa /* 1.0843565e-19 */, 0x00202020 /* 2.95026e-39 */, 0x7fff00ff /* NaN */), 0x7fff00ff /* NaN */),
(
(0x20005eaa /* 1.0873343e-19 */, 0x9e9e9e3a /* -1.6794342e-20 */, 0xff9e009e /* NaN */),
0xff9e009e, /* NaN */
),
((0x20007faa /* 1.0884262e-19 */, 0x9e00611e /* -6.796347e-21 */, 0x7faa0600 /* NaN */), 0x7faa0600 /* NaN */),
(
(0x20007faa /* 1.0884262e-19 */, 0xaa069e1e /* -1.1956449e-13 */, 0xffffecff /* NaN */),
0xffffecff, /* NaN */
),
((0x20025eaa /* 1.104275e-19 */, 0x9e01033a /* -6.82987e-21 */, 0xff9e009e /* NaN */), 0xff9e009e /* NaN */),
((0x3314f400 /* 3.4680852e-8 */, 0x00ff7903 /* 2.3461462e-38 */, 0xffffffdb /* NaN */), 0xffffffdb /* NaN */),
((0x3314f400 /* 3.4680852e-8 */, 0x00ff7903 /* 2.3461462e-38 */, 0xfffffff6 /* NaN */), 0xfffffff6 /* NaN */),
((0x3a218275 /* 0.0006161102 */, 0x3a3a3a3a /* 0.00071040133 */, 0x7f8a063a /* NaN */), 0x7f8a063a /* NaN */),
((0x40000001 /* 2.0000002 */, 0xfefffffe /* -1.7014116e+38 */, 0xfffe40ff /* NaN */), 0xfffe40ff /* NaN */),
((0x50007faa /* 8623401000 */, 0x000011fb /* 6.45e-42 */, 0xff800000 /* -inf */), 0xff800000 /* -inf */),
((0x64007f8b /* 9.481495e+21 */, 0xfa9a8702 /* -4.01176e+35 */, 0xff820000 /* NaN */), 0xff820000 /* NaN */),
((0x6a017faa /* 3.9138577e+25 */, 0x00000070 /* 1.57e-43 */, 0xff80db03 /* NaN */), 0xff80db03 /* NaN */),
((0x6a017faa /* 3.9138577e+25 */, 0x00000070 /* 1.57e-43 */, 0xff80db23 /* NaN */), 0xff80db23 /* NaN */),
(
(0x6e000000 /* 9.9035203e+27 */, 0xdf008000 /* -9259401000000000000 */, 0x7f800000 /* inf */),
0x7f800000, /* inf */
),
((0x7f7fff00 /* 3.4027717e+38 */, 0x02000080 /* 9.404098e-38 */, 0x7fc00000 /* NaN */), 0x7fc00000 /* NaN */),
(
(0xb3eb00ff /* -1.09432214e-7 */, 0x00ffefe2 /* 2.3504105e-38 */, 0xfffffee9 /* NaN */),
0xfffffee9, /* NaN */
),
(
(0xdf0603ff /* -9656842000000000000 */, 0x808000ff /* -1.1755301e-38 */, 0xff9b0000 /* NaN */),
0xff9b0000, /* NaN */
),
(
(
0xf1001101, /* -634154200000000000000000000000 */
0x7f400000, /* 255211780000000000000000000000000000000 */
0x7f800000, /* inf */
),
0x7f800000, /* inf */
),
((0xf5000080 /* -1.6226175e+32 */, 0xc9ffff00 /* -2097120 */, 0xffff7fff /* NaN */), 0xffff7fff /* NaN */),
(
(0xf5ffffff /* -6.4903707e+32 */, 0xff000b09 /* -1.7019848e+38 */, 0xff800000 /* -inf */),
0xff800000, /* -inf */
),
(
(0xf70029e8 /* -2.5994686e+33 */, 0xf7ffff7f /* -1.0384514e+34 */, 0xffff7fff /* NaN */),
0xffff7fff, /* NaN */
),
(
(0xff007faa /* -1.7080405e+38 */, 0xd3fface5 /* -2196234700000 */, 0xffff7f00 /* NaN */),
0xffff7f00, /* NaN */
),
(
(0xff200000 /* -2.1267648e+38 */, 0xe380ffff /* -4.7592594e+21 */, 0xff800000 /* -inf */),
0xff800000, /* -inf */
),
((0xff6d0000 /* -3.1502704e+38 */, 0xc12005ff /* -10.001464 */, 0xff800000 /* -inf */), 0xff800000 /* -inf */),
];

// `f64` FMA bit-patterns which used to produce the wrong output (found by fuzzing).
pub const FUZZ_IEEE64_FMA_CASES_WITH_EXPECTED_OUTPUTS: &[((u64, u64, u64), u64)] = &[
(
(
0x000000000000001e, /* 1.5e-322 */
0x00000000ffdf0000, /* 2.120927281e-314 */
0xffffff8000000000, /* NaN */
),
0xffffff8000000000, /* NaN */
),
(
(
0x000000007fffffff, /* 1.060997895e-314 */
0xff00000000200000, /* -5.486124071348364e+303 */
0xfffd0000000000e9, /* NaN */
),
0xfffd0000000000e9, /* NaN */
),
(
(
0x0000020000e30000, /* 1.086469195027e-311 */
0xff00000011000000, /* -5.48612441622957e+303 */
0xfffd00000000e0e9, /* NaN */
),
0xfffd00000000e0e9, /* NaN */
),
(
(
0x0000040000006400, /* 2.1729237025965e-311 */
0x000000e5ff000000, /* 4.88050742876e-312 */
0xffffffe300000000, /* NaN */
),
0xffffffe300000000, /* NaN */
),
(
(
0x00006a0000000000, /* 5.75824777836336e-310 */
0x005015000018f9f1, /* 3.5783707339010265e-307 */
0x7fffffde00000000, /* NaN */
),
0x7fffffde00000000, /* NaN */
),
(
(
0x00007ffa01000373, /* 6.95208343930866e-310 */
0x0005000000ff107f, /* 6.95335589042254e-309 */
0xffffffff00000005, /* NaN */
),
0xffffffff00000005, /* NaN */
),
(
(
0x0000ff8000000000, /* 1.387955006954565e-309 */
0x0000000001000000, /* 8.289046e-317 */
0xfff0000000000000, /* -inf */
),
0xfff0000000000000, /* -inf */
),
(
(
0x0002a000f6290000, /* 3.650532203442106e-309 */
0x400013fffd000000, /* 2.009765602648258 */
0xfffdfe0000ff9aff, /* NaN */
),
0xfffdfe0000ff9aff, /* NaN */
),
(
(
0x0006000000001700, /* 8.344026969431096e-309 */
0xd9000000da080000, /* -5.164503950933907e+120 */
0xfffffee5000000fd, /* NaN */
),
0xfffffee5000000fd, /* NaN */
),
(
(
0x0006000040000013, /* 8.344032274391576e-309 */
0xfafe036500061100, /* -2.7893890583525793e+284 */
0xffff7fff00001011, /* NaN */
),
0xffff7fff00001011, /* NaN */
),
(
(
0x00f1000000640000, /* 3.873408578194326e-304 */
0xffe6005e00000000, /* -1.2359946076651026e+308 */
0xfffd007000000000, /* NaN */
),
0xfffd007000000000, /* NaN */
),
(
(
0x05203a0080ff0513, /* 5.456081264530354e-284 */
0xf90000000000f7ff, /* -6.924462078599005e+274 */
0xfff0000000000000, /* -inf */
),
0xfff0000000000000, /* -inf */
),
(
(
0x0540400001000513, /* 2.1855837639726535e-283 */
0xee05130640000100, /* -9.522265158052987e+221 */
0x7fff00001004fa01, /* NaN */
),
0x7fff00001004fa01, /* NaN */
),
(
(
0x0540400001000513, /* 2.1855837639726535e-283 */
0xffd8000000000000, /* -6.741349255733685e+307 */
0xfff0001000000000, /* NaN */
),
0xfff0001000000000, /* NaN */
),
(
(
0x054040000100e213, /* 2.1855837639996873e-283 */
0xfbd8000000000000, /* -3.6544927542749997e+288 */
0xfff0ff1000000000, /* NaN */
),
0xfff0ff1000000000, /* NaN */
),
(
(
0x060000000000ff04, /* 8.814425663530262e-280 */
0x00000020ffff0606, /* 7.00258294846e-313 */
0xffffffde00001300, /* NaN */
),
0xffffffde00001300, /* NaN */
),
(
(
0x1306400001000513, /* 5.042468007014986e-217 */
0x00001004fa03ee05, /* 8.7022551317144e-311 */
0xfffc80f7ffff7fff, /* NaN */
),
0xfffc80f7ffff7fff, /* NaN */
),
(
(
0x1306400001000513, /* 5.042468007014986e-217 */
0xa5001004fa01ee05, /* -1.810368898568446e-130 */
0xfffa80f7ff1b7fff, /* NaN */
),
0xfffa80f7ff1b7fff, /* NaN */
),
(
(
0x4006400005130100, /* 2.7812500378059895 */
0x0000ff4000000000, /* 1.38659692964835e-309 */
0x7fffffec4200044b, /* NaN */
),
0x7fffffec4200044b, /* NaN */
),
(
(
0x4100000001000000, /* 131072.00048828125 */
0x0000fffffff00000, /* 1.390671156386347e-309 */
0xfffffe00000040ff, /* NaN */
),
0xfffffe00000040ff, /* NaN */
),
(
(
0x7a7a7a7a7a7a0000, /* 9.61276249042562e+281 */
0xff7a7a7a7a7a7a7a, /* -1.1621116772547446e+306 */
0xfffd007000ef0000, /* NaN */
),
0xfffd007000ef0000, /* NaN */
),
(
(
0x7f000012007ff010, /* 5.4862182545686e+303 */
0x7f0000120091f010, /* 5.486218256005604e+303 */
0xfff0000000000000, /* -inf */
),
0xfff0000000000000, /* -inf */
),
(
(
0x7f0022000a8000f6, /* 5.531663399192155e+303 */
0xff00ebfef0800300, /* -5.802213559159178e+303 */
0x7ff0000000000000, /* inf */
),
0x7ff0000000000000, /* inf */
),
(
(
0x7f06400001000513, /* 7.62914130360521e+303 */
0xff001004fb88f7ff, /* -5.507580309563204e+303 */
0xfffa01ee0513ffff, /* NaN */
),
0xfffa01ee0513ffff, /* NaN */
),
(
(
0xbbbbbb7f01000513, /* -5.872565540268704e-21 */
0x0100bbbbbbbbbbbb, /* 7.625298445452731e-304 */
0xffffff4000004000, /* NaN */
),
0xffffff4000004000, /* NaN */
),
(
(
0xbc00000000400000, /* -1.0842021734952464e-19 */
0x00bc000000004000, /* 3.987332354453194e-305 */
0xfff0000000e20000, /* NaN */
),
0xfff0000000e20000, /* NaN */
),
(
(
0xddff000004000000, /* -6.048387862754913e+144 */
0xff00000000000000, /* -5.486124068793689e+303 */
0xffffff0000000000, /* NaN */
),
0xffffff0000000000, /* NaN */
),
(
(
0xe100051b060c0513, /* -1.759578741202065e+159 */
0xfbfeee0513064110, /* -1.8838766970066999e+289 */
0xffff7fdf00001004, /* NaN */
),
0xffff7fdf00001004, /* NaN */
),
(
(
0xf0000000007ff010, /* -3.1050361903821855e+231 */
0x7f06010800180000, /* 7.54480183807128e+303 */
0x7ff0000000000000, /* inf */
),
0x7ff0000000000000, /* inf */
),
(
(
0xf4ffff05021d7d12, /* -3.753309156386366e+255 */
0xfd100000e8030000, /* -2.5546778042386733e+294 */
0xfff0000000000000, /* -inf */
),
0xfff0000000000000, /* -inf */
),
(
(
0xff0000fff05f0001, /* -5.48746313513839e+303 */
0xff0000fff0800000, /* -5.487463137772898e+303 */
0xfff0000000000000, /* -inf */
),
0xfff0000000000000, /* -inf */
),
];

#[test]
fn fuzz_fma_with_expected_outputs() {
for &((a_bits, b_bits, c_bits), expected_bits) in FUZZ_IEEE32_FMA_CASES_WITH_EXPECTED_OUTPUTS {
let (a, b, c) =
(Single::from_bits(a_bits.into()), Single::from_bits(b_bits.into()), Single::from_bits(c_bits.into()));
assert_eq!(a.mul_add(b, c).value.to_bits(), expected_bits.into());
}
for &((a_bits, b_bits, c_bits), expected_bits) in FUZZ_IEEE64_FMA_CASES_WITH_EXPECTED_OUTPUTS {
let (a, b, c) =
(Double::from_bits(a_bits.into()), Double::from_bits(b_bits.into()), Double::from_bits(c_bits.into()));
assert_eq!(a.mul_add(b, c).value.to_bits(), expected_bits.into());
}
}

0 comments on commit 8270711

Please sign in to comment.