From 88b5e945e01a4599c60ac406d4949cd0329935cb Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 20 Aug 2019 17:51:54 +0200 Subject: [PATCH 01/22] Make <*const/mut T>::offset_from `const fn` --- src/libcore/intrinsics.rs | 4 + src/libcore/ptr/mod.rs | 18 ++++- src/librustc_codegen_llvm/intrinsic.rs | 19 ++++- src/librustc_mir/interpret/intrinsics.rs | 56 +++++++++++++- src/librustc_mir/transform/qualify_consts.rs | 1 + src/librustc_typeck/check/intrinsic.rs | 2 + src/test/ui/consts/offset_from_ub.rs | 44 +++++++++++ src/test/ui/consts/offset_from_ub.stderr | 81 ++++++++++++++++++++ src/test/ui/consts/offset_of.rs | 39 ++++++++++ src/test/ui/offset_from.rs | 15 ++++ 10 files changed, 276 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/consts/offset_from_ub.rs create mode 100644 src/test/ui/consts/offset_from_ub.stderr create mode 100644 src/test/ui/consts/offset_of.rs create mode 100644 src/test/ui/offset_from.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index b240d059114eb..bae7ae2884f90 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1339,6 +1339,10 @@ extern "rust-intrinsic" { /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); + + /// See documentation of `<*const T>::offset_from` for details. + #[cfg(not(bootstrap))] + pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; } // Some functions are defined here because they accidentally got made diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 13ccc9b252a77..a7adaa6a5097a 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -1286,7 +1286,22 @@ impl *const T { /// } /// ``` #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "const_ptr_offset_from")] #[inline] + pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { + let pointee_size = mem::size_of::(); + let ok = 0 < pointee_size && pointee_size <= isize::max_value() as usize; + // assert that the pointee size is valid in a const eval compatible way + // FIXME: do this with a real assert at some point + [()][(!ok) as usize]; + intrinsics::ptr_offset_from(self, origin) + } + + #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[inline] + #[cfg(bootstrap)] + /// bootstrap pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { let pointee_size = mem::size_of::(); assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize); @@ -2013,8 +2028,9 @@ impl *mut T { /// } /// ``` #[unstable(feature = "ptr_offset_from", issue = "41079")] + #[rustc_const_unstable(feature = "const_ptr_offset_from")] #[inline] - pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { + pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized { (self as *const T).offset_from(origin) } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index b7a410c3760cd..e940a42be7dea 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -19,6 +19,7 @@ use rustc::mir::interpret::GlobalId; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc::hir; use syntax::ast::{self, FloatTy}; +use rustc_target::abi::HasDataLayout; use rustc_codegen_ssa::traits::*; @@ -694,6 +695,23 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } + "ptr_offset_from" => { + let ty = substs.type_at(0); + let pointee_size = self.layout_of(ty).size; + + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let a = args[0].immediate(); + let b = args[1].immediate(); + let a = self.ptrtoint(a, self.type_isize()); + let b = self.ptrtoint(b, self.type_isize()); + let d = self.sub(a, b); + let pointee_size = self.const_usize(pointee_size.bytes()); + // this is where the signed magic happens (notice the `s` in `exactsdiv`) + self.exactsdiv(d, pointee_size) + } + _ => bug!("unknown intrinsic '{}'", name), }; @@ -1218,7 +1236,6 @@ fn generic_simd_intrinsic( // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a // vector mask and returns an unsigned integer containing the most // significant bit (MSB) of each lane. - use rustc_target::abi::HasDataLayout; // If the vector has less than 8 lanes, an u8 is returned with zeroed // trailing bits. diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 5fc23b4a69ec5..a04bf7c0f1a18 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -12,7 +12,7 @@ use rustc::mir::BinOp; use rustc::mir::interpret::{InterpResult, Scalar, GlobalId, ConstValue}; use super::{ - Machine, PlaceTy, OpTy, InterpCx, + Machine, PlaceTy, OpTy, InterpCx, ImmTy, }; mod type_name; @@ -236,6 +236,34 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = Scalar::from_uint(truncated_bits, layout.size); self.write_scalar(result, dest)?; } + + "ptr_offset_from" => { + let a = self.read_immediate(args[0])?.to_scalar()?.to_ptr()?; + let b = self.read_immediate(args[1])?.to_scalar()?.to_ptr()?; + if a.alloc_id != b.alloc_id { + throw_ub_format!( + "ptr_offset_from cannot compute offset of pointers into different \ + allocations.", + ); + } + let usize_layout = self.layout_of(self.tcx.types.usize)?; + let a_offset = ImmTy::from_uint(a.offset.bytes(), usize_layout); + let b_offset = ImmTy::from_uint(b.offset.bytes(), usize_layout); + let (val, overflowed, _) = self.overflowing_binary_op( + BinOp::Sub, a_offset, b_offset, + )?; + if overflowed { + throw_ub_format!( + "second argument to `ptr_offset_from` must be smaller than first", + ); + } + let pointee_layout = self.layout_of(substs.type_at(0))?; + let isize_layout = self.layout_of(self.tcx.types.isize)?; + let val = ImmTy::from_scalar(val, isize_layout); + let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout); + self.exact_div(val, size, dest)?; + } + "transmute" => { self.copy_op_transmute(args[0], dest)?; } @@ -340,4 +368,30 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(false); } } + + pub fn exact_div( + &mut self, + a: ImmTy<'tcx, M::PointerTag>, + b: ImmTy<'tcx, M::PointerTag>, + dest: PlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + // Performs an exact division, resulting in undefined behavior where + // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1`. + // First, check x % y != 0. + if self.binary_op(BinOp::Rem, a, b)?.to_bits()? != 0 { + // Then, check if `b` is -1, which is the "min_value / -1" case. + let minus1 = Scalar::from_int(-1, dest.layout.size); + let b = b.to_scalar().unwrap(); + if b == minus1 { + throw_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented") + } else { + throw_ub_format!( + "exact_div: {} cannot be divided by {} without remainder", + a.to_scalar().unwrap(), + b, + ) + } + } + self.binop_ignore_overflow(BinOp::Div, a, b, dest) + } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 387540655f07b..ec9c7a73de735 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -560,6 +560,7 @@ impl Qualif for IsNotPromotable { | "transmute" | "simd_insert" | "simd_extract" + | "ptr_offset_from" => return true, _ => {} diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index aeb2c40e2ef83..0ebdc0672fcb1 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -307,6 +307,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) { (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool])), + "ptr_offset_from" => + (1, vec![ tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0)) ], tcx.types.isize), "unchecked_div" | "unchecked_rem" | "exact_div" => (1, vec![param(0), param(0)], param(0)), "unchecked_shl" | "unchecked_shr" | diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs new file mode 100644 index 0000000000000..07e1be0480cde --- /dev/null +++ b/src/test/ui/consts/offset_from_ub.rs @@ -0,0 +1,44 @@ +#![feature(const_raw_ptr_deref)] +#![feature(const_ptr_offset_from)] +#![feature(ptr_offset_from)] + +#[repr(C)] +struct Struct { + data: u8, + field: u8, +} + +pub const DIFFERENT_ALLOC: usize = { + //~^ NOTE + let uninit = std::mem::MaybeUninit::::uninit(); + let base_ptr: *const Struct = &uninit as *const _ as *const Struct; + let uninit2 = std::mem::MaybeUninit::::uninit(); + let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct; + let offset = unsafe { field_ptr.offset_from(base_ptr) }; + offset as usize +}; + +pub const NOT_PTR: usize = { + //~^ NOTE + unsafe { (42 as *const u8).offset_from(&5u8) as usize } +}; + +pub const NOT_MULTIPLE_OF_SIZE: usize = { + //~^ NOTE + let data = [5u8, 6, 7]; + let base_ptr = data.as_ptr(); + let field_ptr = &data[1] as *const u8 as *const u16; + let offset = unsafe { field_ptr.offset_from(base_ptr as *const u16) }; + offset as usize +}; + +pub const OVERFLOW: usize = { + //~^ NOTE + let uninit = std::mem::MaybeUninit::::uninit(); + let base_ptr: *const Struct = &uninit as *const _ as *const Struct; + let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; + let offset = unsafe { (base_ptr as *const u8).offset_from(field_ptr) }; + offset as usize +}; + +fn main() {} diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr new file mode 100644 index 0000000000000..12185ab5ccda9 --- /dev/null +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -0,0 +1,81 @@ +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + | +LL | intrinsics::ptr_offset_from(self, origin) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | ptr_offset_from cannot compute offset of pointers into different allocations. + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:17:27 + | + ::: $DIR/offset_from_ub.rs:11:1 + | +LL | / pub const DIFFERENT_ALLOC: usize = { +LL | | +LL | | let uninit = std::mem::MaybeUninit::::uninit(); +LL | | let base_ptr: *const Struct = &uninit as *const _ as *const Struct; +... | +LL | | offset as usize +LL | | }; + | |__- + | + = note: `#[deny(const_err)]` on by default + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + | +LL | intrinsics::ptr_offset_from(self, origin) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | a memory access tried to interpret some bytes as a pointer + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:23:14 + | + ::: $DIR/offset_from_ub.rs:21:1 + | +LL | / pub const NOT_PTR: usize = { +LL | | +LL | | unsafe { (42 as *const u8).offset_from(&5u8) as usize } +LL | | }; + | |__- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + | +LL | intrinsics::ptr_offset_from(self, origin) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | exact_div: 1 cannot be divided by 2 without remainder + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:31:27 + | + ::: $DIR/offset_from_ub.rs:26:1 + | +LL | / pub const NOT_MULTIPLE_OF_SIZE: usize = { +LL | | +LL | | let data = [5u8, 6, 7]; +LL | | let base_ptr = data.as_ptr(); +... | +LL | | offset as usize +LL | | }; + | |__- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL + | +LL | intrinsics::ptr_offset_from(self, origin) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | second argument to `ptr_offset_from` must be smaller than first + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:40:27 + | + ::: $DIR/offset_from_ub.rs:35:1 + | +LL | / pub const OVERFLOW: usize = { +LL | | +LL | | let uninit = std::mem::MaybeUninit::::uninit(); +LL | | let base_ptr: *const Struct = &uninit as *const _ as *const Struct; +... | +LL | | offset as usize +LL | | }; + | |__- + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/consts/offset_of.rs b/src/test/ui/consts/offset_of.rs new file mode 100644 index 0000000000000..7b5b4a77d9ae3 --- /dev/null +++ b/src/test/ui/consts/offset_of.rs @@ -0,0 +1,39 @@ +// run-pass + +#![feature(const_raw_ptr_deref)] +#![feature(const_ptr_offset_from)] +#![feature(ptr_offset_from)] + +struct Struct { + field: (), +} + +#[repr(C)] +struct Struct2 { + data: u8, + field: u8, +} + +pub const OFFSET: usize = { + let uninit = std::mem::MaybeUninit::::uninit(); + let base_ptr: *const Struct = &uninit as *const _ as *const Struct; + // The following statement is UB (taking the address of an uninitialized field). + // Const eval doesn't detect this right now, but it may stop compiling at some point + // in the future. + let field_ptr = unsafe { &(*base_ptr).field as *const () as *const u8 }; + let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) }; + offset as usize +}; + +pub const OFFSET_2: usize = { + let uninit = std::mem::MaybeUninit::::uninit(); + let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2; + let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; + let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) }; + offset as usize +}; + +fn main() { + assert_eq!(OFFSET, 0); + assert_eq!(OFFSET_2, 1); +} diff --git a/src/test/ui/offset_from.rs b/src/test/ui/offset_from.rs new file mode 100644 index 0000000000000..cbbb2adf15f91 --- /dev/null +++ b/src/test/ui/offset_from.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(ptr_offset_from)] + +fn main() { + let mut a = [0; 5]; + let ptr1: *mut i32 = &mut a[1]; + let ptr2: *mut i32 = &mut a[3]; + unsafe { + assert_eq!(ptr2.offset_from(ptr1), 2); + assert_eq!(ptr1.offset_from(ptr2), -2); + assert_eq!(ptr1.offset(2), ptr2); + assert_eq!(ptr2.offset(-2), ptr1); + } +} From 4a51801c394337a64850788c18cbf86c4cbfb35f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 18 Oct 2019 12:21:09 +0200 Subject: [PATCH 02/22] Use dedicated method for getting the type size Co-Authored-By: Nikita Popov --- src/librustc_codegen_llvm/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index e940a42be7dea..6c0728d7a07a6 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -697,7 +697,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { "ptr_offset_from" => { let ty = substs.type_at(0); - let pointee_size = self.layout_of(ty).size; + let pointee_size = self.size_of(ty); // This is the same sequence that Clang emits for pointer subtraction. // It can be neither `nsw` nor `nuw` because the input is treated as From 94a6d4b1b88135bf0dc7b24f23b47eaad50d5ea5 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 18 Oct 2019 12:24:05 +0200 Subject: [PATCH 03/22] Adjust const eval code to reflect `offset_from` docs --- src/librustc_mir/interpret/intrinsics.rs | 7 +----- .../consts/{offset_of.rs => offset_from.rs} | 8 +++++++ src/test/ui/consts/offset_from_ub.rs | 9 -------- src/test/ui/consts/offset_from_ub.stderr | 22 +------------------ 4 files changed, 10 insertions(+), 36 deletions(-) rename src/test/ui/consts/{offset_of.rs => offset_from.rs} (77%) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index a04bf7c0f1a18..a2b901029ec54 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -249,14 +249,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let usize_layout = self.layout_of(self.tcx.types.usize)?; let a_offset = ImmTy::from_uint(a.offset.bytes(), usize_layout); let b_offset = ImmTy::from_uint(b.offset.bytes(), usize_layout); - let (val, overflowed, _) = self.overflowing_binary_op( + let (val, _overflowed, _) = self.overflowing_binary_op( BinOp::Sub, a_offset, b_offset, )?; - if overflowed { - throw_ub_format!( - "second argument to `ptr_offset_from` must be smaller than first", - ); - } let pointee_layout = self.layout_of(substs.type_at(0))?; let isize_layout = self.layout_of(self.tcx.types.isize)?; let val = ImmTy::from_scalar(val, isize_layout); diff --git a/src/test/ui/consts/offset_of.rs b/src/test/ui/consts/offset_from.rs similarity index 77% rename from src/test/ui/consts/offset_of.rs rename to src/test/ui/consts/offset_from.rs index 7b5b4a77d9ae3..4d6800681889c 100644 --- a/src/test/ui/consts/offset_of.rs +++ b/src/test/ui/consts/offset_from.rs @@ -33,7 +33,15 @@ pub const OFFSET_2: usize = { offset as usize }; +pub const OVERFLOW: isize = { + let uninit = std::mem::MaybeUninit::::uninit(); + let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2; + let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; + unsafe { (base_ptr as *const u8).offset_from(field_ptr) } +}; + fn main() { assert_eq!(OFFSET, 0); assert_eq!(OFFSET_2, 1); + assert_eq!(OVERFLOW, -1); } diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs index 07e1be0480cde..fedc1af7705a5 100644 --- a/src/test/ui/consts/offset_from_ub.rs +++ b/src/test/ui/consts/offset_from_ub.rs @@ -32,13 +32,4 @@ pub const NOT_MULTIPLE_OF_SIZE: usize = { offset as usize }; -pub const OVERFLOW: usize = { - //~^ NOTE - let uninit = std::mem::MaybeUninit::::uninit(); - let base_ptr: *const Struct = &uninit as *const _ as *const Struct; - let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; - let offset = unsafe { (base_ptr as *const u8).offset_from(field_ptr) }; - offset as usize -}; - fn main() {} diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index 12185ab5ccda9..ad9695f2fc220 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -57,25 +57,5 @@ LL | | offset as usize LL | | }; | |__- -error: any use of this value will cause an error - --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL - | -LL | intrinsics::ptr_offset_from(self, origin) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | second argument to `ptr_offset_from` must be smaller than first - | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:40:27 - | - ::: $DIR/offset_from_ub.rs:35:1 - | -LL | / pub const OVERFLOW: usize = { -LL | | -LL | | let uninit = std::mem::MaybeUninit::::uninit(); -LL | | let base_ptr: *const Struct = &uninit as *const _ as *const Struct; -... | -LL | | offset as usize -LL | | }; - | |__- - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 1c9d88900b2deb2268e302dd1859f707ec26237b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 18 Oct 2019 16:57:19 +0200 Subject: [PATCH 04/22] Review nit Co-Authored-By: Ralf Jung --- src/librustc_mir/interpret/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index a2b901029ec54..e3d3ff70c4e8a 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -249,7 +249,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let usize_layout = self.layout_of(self.tcx.types.usize)?; let a_offset = ImmTy::from_uint(a.offset.bytes(), usize_layout); let b_offset = ImmTy::from_uint(b.offset.bytes(), usize_layout); - let (val, _overflowed, _) = self.overflowing_binary_op( + let (val, _overflowed, _ty) = self.overflowing_binary_op( BinOp::Sub, a_offset, b_offset, )?; let pointee_layout = self.layout_of(substs.type_at(0))?; From 3956c48f06791f407ffeecc8e88fb68b28662ffa Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 18 Oct 2019 19:58:28 +0200 Subject: [PATCH 05/22] Ignore a test on musl because its ui output differs --- src/test/ui/consts/offset_from_ub.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs index fedc1af7705a5..a233c24a7c52c 100644 --- a/src/test/ui/consts/offset_from_ub.rs +++ b/src/test/ui/consts/offset_from_ub.rs @@ -1,3 +1,6 @@ +// ingoring on musl because it's ui output hides libcore backtraces +// ignore-musl + #![feature(const_raw_ptr_deref)] #![feature(const_ptr_offset_from)] #![feature(ptr_offset_from)] From bf83ecf90eac14093b226d27ab74bc6eefcd550c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 19 Oct 2019 13:12:18 +0200 Subject: [PATCH 06/22] Update ui output --- src/test/ui/consts/offset_from_ub.stderr | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index ad9695f2fc220..1460170a108cb 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -5,9 +5,9 @@ LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | ptr_offset_from cannot compute offset of pointers into different allocations. - | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:17:27 + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:20:27 | - ::: $DIR/offset_from_ub.rs:11:1 + ::: $DIR/offset_from_ub.rs:14:1 | LL | / pub const DIFFERENT_ALLOC: usize = { LL | | @@ -27,9 +27,9 @@ LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | a memory access tried to interpret some bytes as a pointer - | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:23:14 + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:26:14 | - ::: $DIR/offset_from_ub.rs:21:1 + ::: $DIR/offset_from_ub.rs:24:1 | LL | / pub const NOT_PTR: usize = { LL | | @@ -44,9 +44,9 @@ LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | exact_div: 1 cannot be divided by 2 without remainder - | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:31:27 + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:34:27 | - ::: $DIR/offset_from_ub.rs:26:1 + ::: $DIR/offset_from_ub.rs:29:1 | LL | / pub const NOT_MULTIPLE_OF_SIZE: usize = { LL | | From fc500368485bd2ebafea6a37da30f49c8be75aac Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Mon, 21 Oct 2019 15:10:32 +0200 Subject: [PATCH 07/22] fixed ac vulnerability --- src/libstd/sys/sgx/abi/entry.S | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S index c35e49b1dc6ea..4f8673a1907d7 100644 --- a/src/libstd/sys/sgx/abi/entry.S +++ b/src/libstd/sys/sgx/abi/entry.S @@ -121,6 +121,16 @@ sgx_entry: fnstcw %gs:tcsls_user_fcw /* reset user state */ cld /* x86-64 ABI requires DF to be unset at function entry/exit */ + +/* making sure AC flag is not set in rflags */ +/* avoid using the 'clac' instruction to be compatible with older compilers */ + push %rcx + pushfq + popq %rcx + and $0xFFFFFFFFFFFBFFFF, %rcx + push %rcx + popfq + /* check for debug buffer pointer */ testb $0xff,DEBUG(%rip) jz .Lskip_debug_init From f6aa64b7b0e2a39708a1baf631f46cf02025cbe9 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 24 Oct 2019 17:13:38 +0200 Subject: [PATCH 08/22] self-profiling: Remove unused methods from profiler. --- src/librustc/util/profiling.rs | 48 ---------------------------------- 1 file changed, 48 deletions(-) diff --git a/src/librustc/util/profiling.rs b/src/librustc/util/profiling.rs index bd02e7f5a14a1..0ca0ac82533b0 100644 --- a/src/librustc/util/profiling.rs +++ b/src/librustc/util/profiling.rs @@ -131,32 +131,6 @@ impl SelfProfilerRef { }) } - /// Start profiling a generic activity. Profiling continues until - /// `generic_activity_end` is called. The RAII-based `generic_activity` - /// usually is the better alternative. - #[inline(always)] - pub fn generic_activity_start(&self, event_id: &str) { - self.non_guard_generic_event( - |profiler| profiler.generic_activity_event_kind, - |profiler| profiler.profiler.alloc_string(event_id), - EventFilter::GENERIC_ACTIVITIES, - TimestampKind::Start, - ); - } - - /// End profiling a generic activity that was started with - /// `generic_activity_start`. The RAII-based `generic_activity` usually is - /// the better alternative. - #[inline(always)] - pub fn generic_activity_end(&self, event_id: &str) { - self.non_guard_generic_event( - |profiler| profiler.generic_activity_event_kind, - |profiler| profiler.profiler.alloc_string(event_id), - EventFilter::GENERIC_ACTIVITIES, - TimestampKind::End, - ); - } - /// Start profiling a query provider. Profiling continues until the /// TimingGuard returned from this call is dropped. #[inline(always)] @@ -238,28 +212,6 @@ impl SelfProfilerRef { TimingGuard::none() })); } - - #[inline(always)] - fn non_guard_generic_event StringId>( - &self, - event_kind: fn(&SelfProfiler) -> StringId, - event_id: F, - event_filter: EventFilter, - timestamp_kind: TimestampKind - ) { - drop(self.exec(event_filter, |profiler| { - let thread_id = thread_id_to_u64(std::thread::current().id()); - - profiler.profiler.record_event( - event_kind(profiler), - event_id(profiler), - thread_id, - timestamp_kind, - ); - - TimingGuard::none() - })); - } } pub struct SelfProfiler { From ee1173a8ffaf51335a4eb7198cd0ce7f508abfd0 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 24 Oct 2019 17:14:38 +0200 Subject: [PATCH 09/22] self-profiling: Update measureme to 0.4.0 and use new RAII-based API. --- Cargo.lock | 4 ++-- src/librustc/Cargo.toml | 2 +- src/librustc/util/profiling.rs | 40 +++++++++------------------------- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index efcbd7b6794f0..8e0db18e1577f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1954,9 +1954,9 @@ dependencies = [ [[package]] name = "measureme" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09de7dafa3aa334bc806447c7e4de69419723312f4b88b80b561dea66601ce8" +checksum = "cd21b0e6e1af976b269ce062038fe5e1b9ca2f817ab7a3af09ec4210aebf0d30" dependencies = [ "byteorder", "memmap", diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 93274ef0c927c..38631224fd359 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -37,4 +37,4 @@ byteorder = { version = "1.3" } chalk-engine = { version = "0.9.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } smallvec = { version = "0.6.8", features = ["union", "may_dangle"] } -measureme = "0.3" +measureme = "0.4" diff --git a/src/librustc/util/profiling.rs b/src/librustc/util/profiling.rs index 0ca0ac82533b0..08cd68655aa5c 100644 --- a/src/librustc/util/profiling.rs +++ b/src/librustc/util/profiling.rs @@ -14,9 +14,12 @@ use measureme::{StringId, TimestampKind}; /// MmapSerializatioSink is faster on macOS and Linux /// but FileSerializationSink is faster on Windows #[cfg(not(windows))] -type Profiler = measureme::Profiler; +type SerializationSink = measureme::MmapSerializationSink; #[cfg(windows)] -type Profiler = measureme::Profiler; +type SerializationSink = measureme::FileSerializationSink; + +type Profiler = measureme::Profiler; + #[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] pub enum ProfileCategory { @@ -298,14 +301,7 @@ impl SelfProfiler { } #[must_use] -pub struct TimingGuard<'a>(Option>); - -struct TimingGuardInternal<'a> { - raw_profiler: &'a Profiler, - event_id: StringId, - event_kind: StringId, - thread_id: u64, -} +pub struct TimingGuard<'a>(Option>); impl<'a> TimingGuard<'a> { #[inline] @@ -316,14 +312,10 @@ impl<'a> TimingGuard<'a> { ) -> TimingGuard<'a> { let thread_id = thread_id_to_u64(std::thread::current().id()); let raw_profiler = &profiler.profiler; - raw_profiler.record_event(event_kind, event_id, thread_id, TimestampKind::Start); - - TimingGuard(Some(TimingGuardInternal { - raw_profiler, - event_kind, - event_id, - thread_id, - })) + let timing_guard = raw_profiler.start_recording_interval_event(event_kind, + event_id, + thread_id); + TimingGuard(Some(timing_guard)) } #[inline] @@ -331,15 +323,3 @@ impl<'a> TimingGuard<'a> { TimingGuard(None) } } - -impl<'a> Drop for TimingGuardInternal<'a> { - #[inline] - fn drop(&mut self) { - self.raw_profiler.record_event( - self.event_kind, - self.event_id, - self.thread_id, - TimestampKind::End - ); - } -} From 9c083068e31e8eb4d4f1d3f649354408d866574c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 24 Oct 2019 17:37:48 +0200 Subject: [PATCH 10/22] self-profiling: Switch query-blocking measurements to RAII-style API. --- src/librustc/ty/query/plumbing.rs | 14 ++++++++++++-- src/librustc/util/profiling.rs | 26 +++++++------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 41b4883793b54..538154b035ac6 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -90,6 +90,10 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { } return TryGetJob::JobCompleted(result); } + + #[cfg(parallel_compiler)] + let query_blocked_prof_timer; + let job = match lock.active.entry((*key).clone()) { Entry::Occupied(entry) => { match *entry.get() { @@ -98,7 +102,9 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { // in another thread has completed. Record how long we wait in the // self-profiler. #[cfg(parallel_compiler)] - tcx.prof.query_blocked_start(Q::NAME); + { + query_blocked_prof_timer = tcx.prof.query_blocked(Q::NAME); + } job.clone() }, @@ -140,7 +146,11 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { #[cfg(parallel_compiler)] { let result = job.r#await(tcx, span); - tcx.prof.query_blocked_end(Q::NAME); + + // This `drop()` is not strictly necessary as the binding + // would go out of scope anyway. But it's good to have an + // explicit marker of how far the measurement goes. + drop(query_blocked_prof_timer); if let Err(cycle) = result { return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle)); diff --git a/src/librustc/util/profiling.rs b/src/librustc/util/profiling.rs index 08cd68655aa5c..5a1b7f3aa4cb8 100644 --- a/src/librustc/util/profiling.rs +++ b/src/librustc/util/profiling.rs @@ -156,26 +156,14 @@ impl SelfProfilerRef { } /// Start profiling a query being blocked on a concurrent execution. - /// Profiling continues until `query_blocked_end` is called. + /// Profiling continues until the TimingGuard returned from this call is + /// dropped. #[inline(always)] - pub fn query_blocked_start(&self, query_name: QueryName) { - self.non_guard_query_event( - |profiler| profiler.query_blocked_event_kind, - query_name, - EventFilter::QUERY_BLOCKED, - TimestampKind::Start, - ); - } - - /// End profiling a query being blocked on a concurrent execution. - #[inline(always)] - pub fn query_blocked_end(&self, query_name: QueryName) { - self.non_guard_query_event( - |profiler| profiler.query_blocked_event_kind, - query_name, - EventFilter::QUERY_BLOCKED, - TimestampKind::End, - ); + pub fn query_blocked(&self, query_name: QueryName) -> TimingGuard<'_> { + self.exec(EventFilter::QUERY_BLOCKED, |profiler| { + let event_id = SelfProfiler::get_query_name_string_id(query_name); + TimingGuard::start(profiler, profiler.query_blocked_event_kind, event_id) + }) } /// Start profiling how long it takes to load a query result from the From dcf343689973ef81d674c1df0f21fc9332c73f3f Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Fri, 25 Oct 2019 10:50:21 +0200 Subject: [PATCH 11/22] Fill tracking issue number for `array_value_iter` and fix Rust version --- src/libcore/array/iter.rs | 20 ++++++++++---------- src/libcore/array/mod.rs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libcore/array/iter.rs b/src/libcore/array/iter.rs index 850a599c6599f..11803238407c8 100644 --- a/src/libcore/array/iter.rs +++ b/src/libcore/array/iter.rs @@ -13,7 +13,7 @@ use super::LengthAtMost32; /// A by-value [array] iterator. /// /// [array]: ../../std/primitive.array.html -#[unstable(feature = "array_value_iter", issue = "0")] +#[unstable(feature = "array_value_iter", issue = "65798")] pub struct IntoIter where [T; N]: LengthAtMost32, @@ -49,7 +49,7 @@ where /// *Note*: this method might never get stabilized and/or removed in the /// future as there will likely be another, preferred way of obtaining this /// iterator (either via `IntoIterator` for arrays or via another way). - #[unstable(feature = "array_value_iter", issue = "0")] + #[unstable(feature = "array_value_iter", issue = "65798")] pub fn new(array: [T; N]) -> Self { // The transmute here is actually safe. The docs of `MaybeUninit` // promise: @@ -95,7 +95,7 @@ where } -#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +#[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Iterator for IntoIter where [T; N]: LengthAtMost32, @@ -141,7 +141,7 @@ where } } -#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +#[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl DoubleEndedIterator for IntoIter where [T; N]: LengthAtMost32, @@ -176,7 +176,7 @@ where } } -#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +#[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Drop for IntoIter where [T; N]: LengthAtMost32, @@ -189,7 +189,7 @@ where } } -#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +#[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl ExactSizeIterator for IntoIter where [T; N]: LengthAtMost32, @@ -204,7 +204,7 @@ where } } -#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +#[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl FusedIterator for IntoIter where [T; N]: LengthAtMost32, @@ -214,13 +214,13 @@ where // elements (that will still be yielded) is the length of the range `alive`. // This range is decremented in length in either `next` or `next_back`. It is // always decremented by 1 in those methods, but only if `Some(_)` is returned. -#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +#[stable(feature = "array_value_iter_impls", since = "1.40.0")] unsafe impl TrustedLen for IntoIter where [T; N]: LengthAtMost32, {} -#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +#[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Clone for IntoIter where [T; N]: LengthAtMost32, @@ -251,7 +251,7 @@ where } } -#[stable(feature = "array_value_iter_impls", since = "1.38.0")] +#[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl fmt::Debug for IntoIter where [T; N]: LengthAtMost32, diff --git a/src/libcore/array/mod.rs b/src/libcore/array/mod.rs index 120658e9a4343..e1ec8b795d04c 100644 --- a/src/libcore/array/mod.rs +++ b/src/libcore/array/mod.rs @@ -18,7 +18,7 @@ use crate::slice::{Iter, IterMut}; mod iter; #[cfg(not(bootstrap))] -#[unstable(feature = "array_value_iter", issue = "0")] +#[unstable(feature = "array_value_iter", issue = "65798")] pub use iter::IntoIter; /// Utility trait implemented only on arrays of fixed size From 4936f96d42eeaa65e4b169113796f29c8c769f39 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 25 Oct 2019 14:07:08 +0200 Subject: [PATCH 12/22] Add [T]::as_ptr_range() and [T]::as_mut_ptr_range(). See https://github.com/rust-lang/rfcs/pull/2791 for motivation. --- src/libcore/slice/mod.rs | 61 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 4e79ea812044b..0770b0c6f9016 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -28,7 +28,7 @@ use crate::fmt; use crate::intrinsics::{assume, exact_div, unchecked_sub, is_aligned_and_not_null}; use crate::isize; use crate::iter::*; -use crate::ops::{FnMut, self}; +use crate::ops::{FnMut, Range, self}; use crate::option::Option; use crate::option::Option::{None, Some}; use crate::result::Result; @@ -407,6 +407,65 @@ impl [T] { self as *mut [T] as *mut T } + /// Returns the two raw pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the size. + /// + /// See [`as_ptr`] for warnings on using these pointers. The end pointer + /// requires extra caution, as it does not point to a valid element in the + /// slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// It can also be useful to check if a reference or pointer to an element + /// refers to an element of this slice: + /// + /// ``` + /// let a = [1,2,3]; + /// let x = &a[1]; + /// let y = &5; + /// assert!(a.as_ptr_range().contains(x)); + /// assert!(!a.as_ptr_range().contains(y)); + /// ``` + /// + /// [`as_ptr`]: #method.as_ptr + #[unstable(feature = "slice_ptr_range", issue = "0")] + #[inline] + pub fn as_ptr_range(&self) -> Range<*const T> { + let start = self.as_ptr(); + let end = unsafe { start.add(self.len()) }; + start..end + } + + /// Returns the two unsafe mutable pointers spanning the slice. + /// + /// The returned range is half-open, which means that the end pointer + /// points *one past* the last element of the slice. This way, an empty + /// slice is represented by two equal pointers, and the difference between + /// the two pointers represents the size of the size. + /// + /// See [`as_mut_ptr`] for warnings on using these pointers. The end + /// pointer requires extra caution, as it does not point to a valid element + /// in the slice. + /// + /// This function is useful for interacting with foreign interfaces which + /// use two pointers to refer to a range of elements in memory, as is + /// common in C++. + /// + /// [`as_mut_ptr`]: #method.as_mut_ptr + #[unstable(feature = "slice_ptr_range", issue = "0")] + #[inline] + pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + let start = self.as_mut_ptr(); + let end = unsafe { start.add(self.len()) }; + start..end + } + /// Swaps two elements in the slice. /// /// # Arguments From f1b69b0a871a5d78504c0dc197e0ebb477de653c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 25 Oct 2019 14:33:07 +0200 Subject: [PATCH 13/22] Add slice_ptr_range tracking issue number. --- src/libcore/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0770b0c6f9016..0a115ce84caad 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -434,7 +434,7 @@ impl [T] { /// ``` /// /// [`as_ptr`]: #method.as_ptr - #[unstable(feature = "slice_ptr_range", issue = "0")] + #[unstable(feature = "slice_ptr_range", issue = "65807")] #[inline] pub fn as_ptr_range(&self) -> Range<*const T> { let start = self.as_ptr(); @@ -458,7 +458,7 @@ impl [T] { /// common in C++. /// /// [`as_mut_ptr`]: #method.as_mut_ptr - #[unstable(feature = "slice_ptr_range", issue = "0")] + #[unstable(feature = "slice_ptr_range", issue = "65807")] #[inline] pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> { let start = self.as_mut_ptr(); From d257c20a1dc97631f6c1cf4a22f32ed80f23e4f1 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Fri, 25 Oct 2019 15:27:48 +0200 Subject: [PATCH 14/22] removed unnecessary push --- src/libstd/sys/sgx/abi/entry.S | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S index 4f8673a1907d7..08aee89fe03de 100644 --- a/src/libstd/sys/sgx/abi/entry.S +++ b/src/libstd/sys/sgx/abi/entry.S @@ -124,7 +124,6 @@ sgx_entry: /* making sure AC flag is not set in rflags */ /* avoid using the 'clac' instruction to be compatible with older compilers */ - push %rcx pushfq popq %rcx and $0xFFFFFFFFFFFBFFFF, %rcx From 34f5d5923f3dff832fbc62a61a062643d78e4c03 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Fri, 25 Oct 2019 15:44:07 +0200 Subject: [PATCH 15/22] cleaning up code --- src/libstd/sys/sgx/abi/entry.S | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S index 08aee89fe03de..f5d9c4338deb5 100644 --- a/src/libstd/sys/sgx/abi/entry.S +++ b/src/libstd/sys/sgx/abi/entry.S @@ -119,16 +119,11 @@ sgx_entry: mov %rbx,%gs:tcsls_tcs_addr stmxcsr %gs:tcsls_user_mxcsr fnstcw %gs:tcsls_user_fcw -/* reset user state */ - cld /* x86-64 ABI requires DF to be unset at function entry/exit */ -/* making sure AC flag is not set in rflags */ -/* avoid using the 'clac' instruction to be compatible with older compilers */ - pushfq - popq %rcx - and $0xFFFFFFFFFFFBFFFF, %rcx - push %rcx - popfq +/* reset user state */ +/* - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */ +/* - AC flag: AEX on misaligned memory accesses leaks side channel info */ + andq $~0x40400, (%rsp) /* check for debug buffer pointer */ testb $0xff,DEBUG(%rip) From de9b660a40728d4c4213f2ec7a1c99a9bc352023 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 25 Oct 2019 15:21:00 +0200 Subject: [PATCH 16/22] Explain why pointer::add in slice::as_ptr_range is safe. --- src/libcore/slice/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0a115ce84caad..185913a47f1a2 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -437,6 +437,23 @@ impl [T] { #[unstable(feature = "slice_ptr_range", issue = "65807")] #[inline] pub fn as_ptr_range(&self) -> Range<*const T> { + // The `add` here is safe, because: + // + // - Both pointers are part of the same object, as pointing directly + // past the object also counts. + // + // - The size of the slice is never larger than isize::MAX bytes, as + // noted here: + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/102#issuecomment-473340447 + // - https://doc.rust-lang.org/reference/behavior-considered-undefined.html + // - https://doc.rust-lang.org/core/slice/fn.from_raw_parts.html#safety + // (This doesn't seem normative yet, but the very same assumption is + // made in many places, including the Index implementation of slices.) + // + // - There is no wrapping around involved, as slices do not wrap past + // the end of the address space. + // + // See the documentation of pointer::add. let start = self.as_ptr(); let end = unsafe { start.add(self.len()) }; start..end @@ -461,6 +478,7 @@ impl [T] { #[unstable(feature = "slice_ptr_range", issue = "65807")] #[inline] pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + // See as_ptr_range() above for why `add` here is safe. let start = self.as_mut_ptr(); let end = unsafe { start.add(self.len()) }; start..end From 5aafa98562a3bd472ae7934f0d192b9cfcb36254 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Fri, 25 Oct 2019 16:06:13 +0200 Subject: [PATCH 17/22] forgot pushfq/popqfq: fixed --- src/libstd/sys/sgx/abi/entry.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S index f5d9c4338deb5..cd26c7ca200b0 100644 --- a/src/libstd/sys/sgx/abi/entry.S +++ b/src/libstd/sys/sgx/abi/entry.S @@ -123,7 +123,9 @@ sgx_entry: /* reset user state */ /* - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */ /* - AC flag: AEX on misaligned memory accesses leaks side channel info */ + pushfq andq $~0x40400, (%rsp) + popfq /* check for debug buffer pointer */ testb $0xff,DEBUG(%rip) From 0d21d257c9691983fd51e7d5d9ace4de8933114c Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Tue, 22 Oct 2019 13:54:09 -0400 Subject: [PATCH 18/22] Remove unneeded pointer casting --- src/liballoc/string.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 639124e26cc20..108c91fba1ff8 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -194,9 +194,9 @@ use crate::vec::Vec; /// ``` /// use std::mem; /// -/// let story = String::from("Once upon a time..."); +/// let mut story = String::from("Once upon a time..."); /// -/// let ptr = story.as_ptr(); +/// let ptr = story.as_mut_ptr(); /// let len = story.len(); /// let capacity = story.capacity(); /// @@ -209,7 +209,7 @@ use crate::vec::Vec; /// // We can re-build a String out of ptr, len, and capacity. This is all /// // unsafe because we are responsible for making sure the components are /// // valid: -/// let s = unsafe { String::from_raw_parts(ptr as *mut _, len, capacity) } ; +/// let s = unsafe { String::from_raw_parts(ptr, len, capacity) } ; /// /// assert_eq!(String::from("Once upon a time..."), s); /// ``` @@ -676,14 +676,14 @@ impl String { /// use std::mem; /// /// unsafe { - /// let s = String::from("hello"); - /// let ptr = s.as_ptr(); + /// let mut s = String::from("hello"); + /// let ptr = s.as_mut_ptr(); /// let len = s.len(); /// let capacity = s.capacity(); /// /// mem::forget(s); /// - /// let s = String::from_raw_parts(ptr as *mut _, len, capacity); + /// let s = String::from_raw_parts(ptr, len, capacity); /// /// assert_eq!(String::from("hello"), s); /// } From dce8fabc62ed393152c53c65c492c8f3ae324eda Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Tue, 22 Oct 2019 15:40:22 -0400 Subject: [PATCH 19/22] Use ManuallyDrop in examples for {Vec,String}::from_raw_parts --- src/liballoc/string.rs | 16 +++++++++------- src/liballoc/vec.rs | 10 +++++----- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 108c91fba1ff8..1d0faeccecf1d 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -194,7 +194,10 @@ use crate::vec::Vec; /// ``` /// use std::mem; /// -/// let mut story = String::from("Once upon a time..."); +/// let story = String::from("Once upon a time..."); +/// +/// // Prevent automatically dropping the String's data +/// let mut story = mem::ManuallyDrop::new(story); /// /// let ptr = story.as_mut_ptr(); /// let len = story.len(); @@ -203,9 +206,6 @@ use crate::vec::Vec; /// // story has nineteen bytes /// assert_eq!(19, len); /// -/// // Now that we have our parts, we throw the story away. -/// mem::forget(story); -/// /// // We can re-build a String out of ptr, len, and capacity. This is all /// // unsafe because we are responsible for making sure the components are /// // valid: @@ -676,13 +676,15 @@ impl String { /// use std::mem; /// /// unsafe { - /// let mut s = String::from("hello"); + /// let s = String::from("hello"); + /// + /// // Prevent automatically dropping the String's data + /// let mut s = mem::ManuallyDrop::new(s); + /// /// let ptr = s.as_mut_ptr(); /// let len = s.len(); /// let capacity = s.capacity(); /// - /// mem::forget(s); - /// /// let s = String::from_raw_parts(ptr, len, capacity); /// /// assert_eq!(String::from("hello"), s); diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 6350b189c5faa..c8fb897123475 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -389,7 +389,11 @@ impl Vec { /// use std::ptr; /// use std::mem; /// - /// let mut v = vec![1, 2, 3]; + /// let v = vec![1, 2, 3]; + /// + /// // Prevent running `v`'s destructor so we are in complete control + /// // of the allocation. + /// let mut v = mem::ManuallyDrop::new(v); /// /// // Pull out the various important pieces of information about `v` /// let p = v.as_mut_ptr(); @@ -397,10 +401,6 @@ impl Vec { /// let cap = v.capacity(); /// /// unsafe { - /// // Cast `v` into the void: no destructor run, so we are in - /// // complete control of the allocation to which `p` points. - /// mem::forget(v); - /// /// // Overwrite memory with 4, 5, 6 /// for i in 0..len as isize { /// ptr::write(p.offset(i), 4 + i); From 6600cf604091a99bba990d41b93885b40c02a97d Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Tue, 22 Oct 2019 12:48:52 -0400 Subject: [PATCH 20/22] Add {String,Vec}::into_raw_parts --- src/liballoc/string.rs | 33 +++++++++++++++++++++++++++++++++ src/liballoc/vec.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/libcore/intrinsics.rs | 1 + 3 files changed, 73 insertions(+) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 1d0faeccecf1d..d9927c642b2d8 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -196,6 +196,7 @@ use crate::vec::Vec; /// /// let story = String::from("Once upon a time..."); /// +// FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent automatically dropping the String's data /// let mut story = mem::ManuallyDrop::new(story); /// @@ -647,6 +648,37 @@ impl String { decode_utf16(v.iter().cloned()).map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)).collect() } + /// Decomposes a `String` into its raw components. + /// + /// Returns the raw pointer to the underlying data, the length of + /// the string (in bytes), and the allocated capacity of the data + /// (in bytes). These are the same arguments in the same order as + /// the arguments to [`from_raw_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `String`. The only way to do + /// this is to convert the raw pointer, length, and capacity back + /// into a `String` with the [`from_raw_parts`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_raw_parts`]: #method.from_raw_parts + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_raw_parts)] + /// let s = String::from("hello"); + /// + /// let (ptr, len, cap) = s.into_raw_parts(); + /// + /// let rebuilt = unsafe { String::from_raw_parts(ptr, len, cap) }; + /// assert_eq!(rebuilt, "hello"); + /// ``` + #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_raw_parts(self) -> (*mut u8, usize, usize) { + self.vec.into_raw_parts() + } + /// Creates a new `String` from a length, capacity, and pointer. /// /// # Safety @@ -678,6 +710,7 @@ impl String { /// unsafe { /// let s = String::from("hello"); /// + // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent automatically dropping the String's data /// let mut s = mem::ManuallyDrop::new(s); /// diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index c8fb897123475..641f9eafa8d23 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -358,6 +358,44 @@ impl Vec { } } + /// Decomposes a `Vec` into its raw components. + /// + /// Returns the raw pointer to the underlying data, the length of + /// the vector (in elements), and the allocated capacity of the + /// data (in elements). These are the same arguments in the same + /// order as the arguments to [`from_raw_parts`]. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `Vec`. The only way to do + /// this is to convert the raw pointer, length, and capacity back + /// into a `Vec` with the [`from_raw_parts`] function, allowing + /// the destructor to perform the cleanup. + /// + /// [`from_raw_parts`]: #method.from_raw_parts + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_into_raw_parts)] + /// let v: Vec = vec![-1, 0, 1]; + /// + /// let (ptr, len, cap) = v.into_raw_parts(); + /// + /// let rebuilt = unsafe { + /// // We can now make changes to the components, such as + /// // transmuting the raw pointer to a compatible type. + /// let ptr = ptr as *mut u32; + /// + /// Vec::from_raw_parts(ptr, len, cap) + /// }; + /// assert_eq!(rebuilt, [4294967295, 0, 1]); + /// ``` + #[unstable(feature = "vec_into_raw_parts", reason = "new API", issue = "65816")] + pub fn into_raw_parts(self) -> (*mut T, usize, usize) { + let mut me = mem::ManuallyDrop::new(self); + (me.as_mut_ptr(), me.len(), me.capacity()) + } + /// Creates a `Vec` directly from the raw components of another vector. /// /// # Safety @@ -391,6 +429,7 @@ impl Vec { /// /// let v = vec![1, 2, 3]; /// + // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control /// // of the allocation. /// let mut v = mem::ManuallyDrop::new(v); diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index b240d059114eb..4655d39fb8f1f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -874,6 +874,7 @@ extern "rust-intrinsic" { /// // the original inner type (`&i32`) to the converted inner type /// // (`Option<&i32>`), so read the nomicon pages linked above. /// let v_from_raw = unsafe { + // FIXME Update this when vec_into_raw_parts is stabilized /// // Ensure the original vector is not dropped. /// let mut v_clone = std::mem::ManuallyDrop::new(v_clone); /// Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut Option<&i32>, From dfcfca28ad1321aff82503ebfffd40cf6476a7a2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 24 Oct 2019 03:21:23 +0200 Subject: [PATCH 21/22] Take out an insurance policy in case `iter.size_hint()` lies, underreporting the number of elements. --- src/librustc/ty/context.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index f958a7e357b39..0f7d5d9a25e61 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2930,14 +2930,18 @@ impl InternIteratorElement for Result { // lower bounds from `size_hint` agree they are correct. Ok(match iter.size_hint() { (1, Some(1)) => { - f(&[iter.next().unwrap()?]) + let t0 = iter.next().unwrap()?; + assert!(iter.next().is_none()); + f(&[t0]) } (2, Some(2)) => { let t0 = iter.next().unwrap()?; let t1 = iter.next().unwrap()?; + assert!(iter.next().is_none()); f(&[t0, t1]) } (0, Some(0)) => { + assert!(iter.next().is_none()); f(&[]) } _ => { From 381c4425b7d0f428df6576f085ea03b1d42e06af Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 25 Oct 2019 17:22:03 +0200 Subject: [PATCH 22/22] Fix slice::as_ptr_range doctest. --- src/libcore/slice/mod.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 185913a47f1a2..cdada1252d2bf 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -422,15 +422,18 @@ impl [T] { /// use two pointers to refer to a range of elements in memory, as is /// common in C++. /// - /// It can also be useful to check if a reference or pointer to an element - /// refers to an element of this slice: + /// It can also be useful to check if a pointer to an element refers to an + /// element of this slice: /// /// ``` - /// let a = [1,2,3]; - /// let x = &a[1]; - /// let y = &5; - /// assert!(a.as_ptr_range().contains(x)); - /// assert!(!a.as_ptr_range().contains(y)); + /// #![feature(slice_ptr_range)] + /// + /// let a = [1, 2, 3]; + /// let x = &a[1] as *const _; + /// let y = &5 as *const _; + /// + /// assert!(a.as_ptr_range().contains(&x)); + /// assert!(!a.as_ptr_range().contains(&y)); /// ``` /// /// [`as_ptr`]: #method.as_ptr