Skip to content

Commit bdce1dd

Browse files
committed
Auto merge of #1785 - Smittyvb:fast-math-ub, r=RalfJung
Throw UB if f*_fast intrinsic called with non-finite value Calling these intrinsics with non-finite values is undefined behaviour, since they result in `f*` intrinsics in LLVM with the `fast` flag, and `fast` math on non-finite values results in `poison` values. (technically LLVM only considers it UB upon _using_ the value, but that shouldn't make much of a difference)
2 parents 43ae314 + e0e59f6 commit bdce1dd

File tree

4 files changed

+47
-0
lines changed

4 files changed

+47
-0
lines changed

src/shims/intrinsics.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
173173
"frem_fast" => mir::BinOp::Rem,
174174
_ => bug!(),
175175
};
176+
let float_finite = |x: ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> {
177+
Ok(match x.layout.ty.kind() {
178+
ty::Float(FloatTy::F32) => x.to_scalar()?.to_f32()?.is_finite(),
179+
ty::Float(FloatTy::F64) => x.to_scalar()?.to_f64()?.is_finite(),
180+
_ => bug!(
181+
"`{}` called with non-float input type {:?}",
182+
intrinsic_name,
183+
x.layout.ty
184+
),
185+
})
186+
};
187+
match (float_finite(a)?, float_finite(b)?) {
188+
(false, false) => throw_ub_format!(
189+
"`{}` intrinsic called with non-finite value as both parameters",
190+
intrinsic_name,
191+
),
192+
(false, _) => throw_ub_format!(
193+
"`{}` intrinsic called with non-finite value as first parameter",
194+
intrinsic_name,
195+
),
196+
(_, false) => throw_ub_format!(
197+
"`{}` intrinsic called with non-finite value as second parameter",
198+
intrinsic_name,
199+
),
200+
_ => {}
201+
}
176202
this.binop_ignore_overflow(op, &a, &b, dest)?;
177203
}
178204

tests/compile-fail/fast_math_both.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(core_intrinsics)]
2+
3+
fn main() {
4+
unsafe {
5+
let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR `fsub_fast` intrinsic called with non-finite value as both parameters
6+
}
7+
}

tests/compile-fail/fast_math_first.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(core_intrinsics)]
2+
3+
fn main() {
4+
unsafe {
5+
let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR `frem_fast` intrinsic called with non-finite value as first parameter
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(core_intrinsics)]
2+
3+
fn main() {
4+
unsafe {
5+
let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); //~ ERROR `fmul_fast` intrinsic called with non-finite value as second parameter
6+
}
7+
}

0 commit comments

Comments
 (0)