From 58af73c370df9074961ee78dc9263f60afe0c9af Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 6 Sep 2018 13:13:07 +0200 Subject: [PATCH 1/3] Add unchecked_shl/shr checks for intrinsics --- src/librustc_mir/interpret/intrinsics.rs | 32 ++++++++++++++++--- src/test/ui/consts/const-int-unchecked.rs | 21 ++++++++++++ src/test/ui/consts/const-int-unchecked.stderr | 20 ++++++++++++ 3 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/consts/const-int-unchecked.rs create mode 100644 src/test/ui/consts/const-int-unchecked.stderr diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 8cdb0e37f5507..0f122209baff4 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -105,8 +105,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { | "overflowing_add" | "overflowing_sub" | "overflowing_mul" - | "unchecked_shl" - | "unchecked_shr" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => { @@ -116,8 +114,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { "overflowing_add" => (BinOp::Add, true), "overflowing_sub" => (BinOp::Sub, true), "overflowing_mul" => (BinOp::Mul, true), - "unchecked_shl" => (BinOp::Shl, true), - "unchecked_shr" => (BinOp::Shr, true), "add_with_overflow" => (BinOp::Add, false), "sub_with_overflow" => (BinOp::Sub, false), "mul_with_overflow" => (BinOp::Mul, false), @@ -129,6 +125,34 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { self.binop_with_overflow(bin_op, lhs, rhs, dest)?; } } + "unchecked_shl" | "unchecked_shr" => { + let bits = dest.layout.size.bytes() as u128 * 8; + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + let r_ty = substs.type_at(0); + let r_layout_of = self.layout_of(r_ty)?; + let r_val = r.to_scalar()?.to_bits(r_layout_of.size)?; + let bin_op = match intrinsic_name { + "unchecked_shl" => { + if r_val >= bits { + return err!(Intrinsic( + format!("Overflowing shift by {} in unchecked_shl", r_val), + )); + } + BinOp::Shl + }, + "unchecked_shr" => { + if r_val >= bits { + return err!(Intrinsic( + format!("Overflowing shift by {} in unchecked_shr", r_val), + )); + } + BinOp::Shr + }, + _ => bug!("Already checked for int ops") + }; + self.binop_ignore_overflow(bin_op, l, r, dest)?; + } "transmute" => { // Go through an allocation, to make sure the completely different layouts // do not pose a problem. (When the user transmutes through a union, diff --git a/src/test/ui/consts/const-int-unchecked.rs b/src/test/ui/consts/const-int-unchecked.rs new file mode 100644 index 0000000000000..cbf855633fd2d --- /dev/null +++ b/src/test/ui/consts/const-int-unchecked.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(core_intrinsics)] + +use std::intrinsics; + +const SHR: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; +//^~ ERROR: Overflowing shift by 8 in unchecked_shr +const SHL: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; +//^~ ERROR: Overflowing shift by 8 in unchecked_shl + +fn main() { +} diff --git a/src/test/ui/consts/const-int-unchecked.stderr b/src/test/ui/consts/const-int-unchecked.stderr new file mode 100644 index 0000000000000..b8fd0facbc1ae --- /dev/null +++ b/src/test/ui/consts/const-int-unchecked.stderr @@ -0,0 +1,20 @@ +error: this constant cannot be used + --> $DIR/const-int-unchecked.rs:15:1 + | +LL | const SHR: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | | + | Overflowing shift by 8 in unchecked_shr + | + = note: #[deny(const_err)] on by default + +error: this constant cannot be used + --> $DIR/const-int-unchecked.rs:17:1 + | +LL | const SHL: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^ + | | + | Overflowing shift by 8 in unchecked_shl + +error: aborting due to 2 previous errors + From 92dd526a4e8633b95754e2a8e2ef7169c30706f6 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 6 Sep 2018 13:54:27 +0200 Subject: [PATCH 2/3] Move check out of the match on the intrinsic name --- src/librustc_mir/interpret/intrinsics.rs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 0f122209baff4..8637903bd71d5 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -132,23 +132,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let r_ty = substs.type_at(0); let r_layout_of = self.layout_of(r_ty)?; let r_val = r.to_scalar()?.to_bits(r_layout_of.size)?; + if r_val >= bits { + return err!(Intrinsic( + format!("Overflowing shift by {} in {}", r_val, intrinsic_name), + )); + } let bin_op = match intrinsic_name { - "unchecked_shl" => { - if r_val >= bits { - return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shl", r_val), - )); - } - BinOp::Shl - }, - "unchecked_shr" => { - if r_val >= bits { - return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shr", r_val), - )); - } - BinOp::Shr - }, + "unchecked_shl" => BinOp::Shl, + "unchecked_shr" => BinOp::Shr, _ => bug!("Already checked for int ops") }; self.binop_ignore_overflow(bin_op, l, r, dest)?; From 43eb9259ec92561033969118d1cc071a91f86084 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 6 Sep 2018 15:11:56 +0200 Subject: [PATCH 3/3] Use binary_op_val instead of doing the check manually. --- src/librustc_mir/interpret/intrinsics.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 8637903bd71d5..48085c2145418 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -126,23 +126,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } } "unchecked_shl" | "unchecked_shr" => { - let bits = dest.layout.size.bytes() as u128 * 8; let l = self.read_value(args[0])?; let r = self.read_value(args[1])?; - let r_ty = substs.type_at(0); - let r_layout_of = self.layout_of(r_ty)?; - let r_val = r.to_scalar()?.to_bits(r_layout_of.size)?; - if r_val >= bits { - return err!(Intrinsic( - format!("Overflowing shift by {} in {}", r_val, intrinsic_name), - )); - } let bin_op = match intrinsic_name { "unchecked_shl" => BinOp::Shl, "unchecked_shr" => BinOp::Shr, _ => bug!("Already checked for int ops") }; - self.binop_ignore_overflow(bin_op, l, r, dest)?; + let (val, overflowed) = self.binary_op_val(bin_op, l, r)?; + if overflowed { + let layout = self.layout_of(substs.type_at(0))?; + let r_val = r.to_scalar()?.to_bits(layout.size)?; + return err!(Intrinsic( + format!("Overflowing shift by {} in {}", r_val, intrinsic_name), + )); + } + self.write_scalar(val, dest)?; } "transmute" => { // Go through an allocation, to make sure the completely different layouts