From da0c7c664ba19339c606b3384ef6eebb6c0e4105 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 13:07:36 +0100 Subject: [PATCH 1/5] Miri: offset_from: do int-to-ptr casts when needed --- src/librustc_mir/interpret/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index c08e4c896094b..0b8e3ff6736f9 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -251,8 +251,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } "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()?; + let a = self.force_ptr(self.read_immediate(args[0])?.to_scalar()?)?; + let b = self.force_ptr(self.read_immediate(args[1])?.to_scalar()?)?; if a.alloc_id != b.alloc_id { throw_ub_format!( "ptr_offset_from cannot compute offset of pointers into different \ From 047e702c66ec04d44366210251ae7189ac4bf20a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 13:24:27 +0100 Subject: [PATCH 2/5] Miri: ptr_offset_from: support offset_from with twice the same non-null integer --- src/librustc_mir/interpret/intrinsics.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 0b8e3ff6736f9..990e3007755be 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -251,8 +251,26 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } "ptr_offset_from" => { - let a = self.force_ptr(self.read_immediate(args[0])?.to_scalar()?)?; - let b = self.force_ptr(self.read_immediate(args[1])?.to_scalar()?)?; + let isize_layout = self.layout_of(self.tcx.types.isize)?; + let a = self.read_immediate(args[0])?.to_scalar()?; + let b = self.read_immediate(args[1])?.to_scalar()?; + + // Special case: if both scalars are *equal integers* + // and not NULL, their offset is 0. + // This is the dual to the special exception for offset-by-0 + // in the inbounds pointer offset operation. + if a.is_bits() && b.is_bits() { + let a = a.to_usize(self)?; + let b = b.to_usize(self)?; + if a == b && a != 0 { + self.write_scalar(Scalar::from_int(0, isize_layout.size), dest)?; + return Ok(true); + } + } + + // General case: we need two pointers. + let a = self.force_ptr(a)?; + let b = self.force_ptr(b)?; if a.alloc_id != b.alloc_id { throw_ub_format!( "ptr_offset_from cannot compute offset of pointers into different \ @@ -266,7 +284,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { BinOp::Sub, a_offset, b_offset, )?; 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)?; From 3c944feb658575f0afae2e148e058ad3599926df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 13:30:00 +0100 Subject: [PATCH 3/5] test offset_from with two integers --- src/test/ui/consts/offset_from.rs | 6 +++++ src/test/ui/consts/offset_from_ub.rs | 11 +++++++--- src/test/ui/consts/offset_from_ub.stderr | 28 +++++++++++++++++++----- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/test/ui/consts/offset_from.rs b/src/test/ui/consts/offset_from.rs index 4d6800681889c..8c1b27842628d 100644 --- a/src/test/ui/consts/offset_from.rs +++ b/src/test/ui/consts/offset_from.rs @@ -40,8 +40,14 @@ pub const OVERFLOW: isize = { unsafe { (base_ptr as *const u8).offset_from(field_ptr) } }; +pub const OFFSET_EQUAL_INTS: isize = { + let ptr = 1 as *const u8; + unsafe { ptr.offset_from(ptr) } +}; + fn main() { assert_eq!(OFFSET, 0); assert_eq!(OFFSET_2, 1); assert_eq!(OVERFLOW, -1); + assert_eq!(OFFSET_EQUAL_INTS, 0); } diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs index 18b4d7271260f..c96d62cd92356 100644 --- a/src/test/ui/consts/offset_from_ub.rs +++ b/src/test/ui/consts/offset_from_ub.rs @@ -25,13 +25,18 @@ pub const NOT_PTR: usize = { unsafe { (42 as *const u8).offset_from(&5u8) as usize } }; -pub const NOT_MULTIPLE_OF_SIZE: usize = { +pub const NOT_MULTIPLE_OF_SIZE: isize = { //~^ 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 + unsafe { field_ptr.offset_from(base_ptr as *const u16) } +}; + +pub const OFFSET_FROM_NULL: isize = { + //~^ NOTE + let ptr = 0 as *const u8; + unsafe { ptr.offset_from(ptr) } }; fn main() {} diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index 289128b4a170b..1015b9cf7fcc4 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -44,18 +44,36 @@ 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:33:27 + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:33:14 | ::: $DIR/offset_from_ub.rs:28:1 | -LL | / pub const NOT_MULTIPLE_OF_SIZE: usize = { +LL | / pub const NOT_MULTIPLE_OF_SIZE: isize = { LL | | LL | | let data = [5u8, 6, 7]; LL | | let base_ptr = data.as_ptr(); -... | -LL | | offset as usize +LL | | let field_ptr = &data[1] as *const u8 as *const u16; +LL | | unsafe { field_ptr.offset_from(base_ptr as *const u16) } +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) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | invalid use of NULL pointer + | inside call to `std::ptr::::offset_from` at $DIR/offset_from_ub.rs:39:14 + | + ::: $DIR/offset_from_ub.rs:36:1 + | +LL | / pub const OFFSET_FROM_NULL: isize = { +LL | | +LL | | let ptr = 0 as *const u8; +LL | | unsafe { ptr.offset_from(ptr) } LL | | }; | |__- -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors From 21d284b6f0d62dfd284249a9e059b72e4fcfca87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 13:31:29 +0100 Subject: [PATCH 4/5] also test different integers --- src/test/ui/consts/offset_from_ub.rs | 7 +++++++ src/test/ui/consts/offset_from_ub.stderr | 21 ++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs index c96d62cd92356..c9030915620a8 100644 --- a/src/test/ui/consts/offset_from_ub.rs +++ b/src/test/ui/consts/offset_from_ub.rs @@ -39,4 +39,11 @@ pub const OFFSET_FROM_NULL: isize = { unsafe { ptr.offset_from(ptr) } }; +pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC + //~^ NOTE + let ptr1 = 8 as *const u8; + let ptr2 = 16 as *const u8; + unsafe { ptr2.offset_from(ptr1) } +}; + fn main() {} diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index 1015b9cf7fcc4..1bd09034bfc91 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -75,5 +75,24 @@ LL | | unsafe { ptr.offset_from(ptr) } LL | | }; | |__- -error: aborting due to 4 previous errors +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:46:14 + | + ::: $DIR/offset_from_ub.rs:42:1 + | +LL | / pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC +LL | | +LL | | let ptr1 = 8 as *const u8; +LL | | let ptr2 = 16 as *const u8; +LL | | unsafe { ptr2.offset_from(ptr1) } +LL | | }; + | |__- + +error: aborting due to 5 previous errors From a593b5419901774c134e18433452c4dd5f7ff648 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Nov 2019 10:41:19 +0100 Subject: [PATCH 5/5] expand comment explaining integer exception --- src/librustc_mir/interpret/intrinsics.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 990e3007755be..04032847385e9 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -256,9 +256,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let b = self.read_immediate(args[1])?.to_scalar()?; // Special case: if both scalars are *equal integers* - // and not NULL, their offset is 0. + // and not NULL, we pretend there is an allocation of size 0 right there, + // and their offset is 0. (There's never a valid object at NULL, making it an + // exception from the exception.) // This is the dual to the special exception for offset-by-0 - // in the inbounds pointer offset operation. + // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`). if a.is_bits() && b.is_bits() { let a = a.to_usize(self)?; let b = b.to_usize(self)?;