Skip to content

Commit 3a1b3b3

Browse files
committed
Auto merge of #66083 - RalfJung:miri-offset-from, r=oli-obk
fix Miri offset_from This is needed to make rust-lang/miri#1032 pass.
2 parents d1fff4a + a593b54 commit 3a1b3b3

File tree

4 files changed

+85
-11
lines changed

4 files changed

+85
-11
lines changed

src/librustc_mir/interpret/intrinsics.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,28 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
251251
}
252252

253253
"ptr_offset_from" => {
254-
let a = self.read_immediate(args[0])?.to_scalar()?.to_ptr()?;
255-
let b = self.read_immediate(args[1])?.to_scalar()?.to_ptr()?;
254+
let isize_layout = self.layout_of(self.tcx.types.isize)?;
255+
let a = self.read_immediate(args[0])?.to_scalar()?;
256+
let b = self.read_immediate(args[1])?.to_scalar()?;
257+
258+
// Special case: if both scalars are *equal integers*
259+
// and not NULL, we pretend there is an allocation of size 0 right there,
260+
// and their offset is 0. (There's never a valid object at NULL, making it an
261+
// exception from the exception.)
262+
// This is the dual to the special exception for offset-by-0
263+
// in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`).
264+
if a.is_bits() && b.is_bits() {
265+
let a = a.to_usize(self)?;
266+
let b = b.to_usize(self)?;
267+
if a == b && a != 0 {
268+
self.write_scalar(Scalar::from_int(0, isize_layout.size), dest)?;
269+
return Ok(true);
270+
}
271+
}
272+
273+
// General case: we need two pointers.
274+
let a = self.force_ptr(a)?;
275+
let b = self.force_ptr(b)?;
256276
if a.alloc_id != b.alloc_id {
257277
throw_ub_format!(
258278
"ptr_offset_from cannot compute offset of pointers into different \
@@ -266,7 +286,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
266286
BinOp::Sub, a_offset, b_offset,
267287
)?;
268288
let pointee_layout = self.layout_of(substs.type_at(0))?;
269-
let isize_layout = self.layout_of(self.tcx.types.isize)?;
270289
let val = ImmTy::from_scalar(val, isize_layout);
271290
let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
272291
self.exact_div(val, size, dest)?;

src/test/ui/consts/offset_from.rs

+6
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,14 @@ pub const OVERFLOW: isize = {
4040
unsafe { (base_ptr as *const u8).offset_from(field_ptr) }
4141
};
4242

43+
pub const OFFSET_EQUAL_INTS: isize = {
44+
let ptr = 1 as *const u8;
45+
unsafe { ptr.offset_from(ptr) }
46+
};
47+
4348
fn main() {
4449
assert_eq!(OFFSET, 0);
4550
assert_eq!(OFFSET_2, 1);
4651
assert_eq!(OVERFLOW, -1);
52+
assert_eq!(OFFSET_EQUAL_INTS, 0);
4753
}

src/test/ui/consts/offset_from_ub.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,25 @@ pub const NOT_PTR: usize = {
2525
unsafe { (42 as *const u8).offset_from(&5u8) as usize }
2626
};
2727

28-
pub const NOT_MULTIPLE_OF_SIZE: usize = {
28+
pub const NOT_MULTIPLE_OF_SIZE: isize = {
2929
//~^ NOTE
3030
let data = [5u8, 6, 7];
3131
let base_ptr = data.as_ptr();
3232
let field_ptr = &data[1] as *const u8 as *const u16;
33-
let offset = unsafe { field_ptr.offset_from(base_ptr as *const u16) };
34-
offset as usize
33+
unsafe { field_ptr.offset_from(base_ptr as *const u16) }
34+
};
35+
36+
pub const OFFSET_FROM_NULL: isize = {
37+
//~^ NOTE
38+
let ptr = 0 as *const u8;
39+
unsafe { ptr.offset_from(ptr) }
40+
};
41+
42+
pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC
43+
//~^ NOTE
44+
let ptr1 = 8 as *const u8;
45+
let ptr2 = 16 as *const u8;
46+
unsafe { ptr2.offset_from(ptr1) }
3547
};
3648

3749
fn main() {}

src/test/ui/consts/offset_from_ub.stderr

+42-5
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,55 @@ LL | intrinsics::ptr_offset_from(self, origin)
4444
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4545
| |
4646
| exact_div: 1 cannot be divided by 2 without remainder
47-
| inside call to `std::ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:33:27
47+
| inside call to `std::ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:33:14
4848
|
4949
::: $DIR/offset_from_ub.rs:28:1
5050
|
51-
LL | / pub const NOT_MULTIPLE_OF_SIZE: usize = {
51+
LL | / pub const NOT_MULTIPLE_OF_SIZE: isize = {
5252
LL | |
5353
LL | | let data = [5u8, 6, 7];
5454
LL | | let base_ptr = data.as_ptr();
55-
... |
56-
LL | | offset as usize
55+
LL | | let field_ptr = &data[1] as *const u8 as *const u16;
56+
LL | | unsafe { field_ptr.offset_from(base_ptr as *const u16) }
57+
LL | | };
58+
| |__-
59+
60+
error: any use of this value will cause an error
61+
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
62+
|
63+
LL | intrinsics::ptr_offset_from(self, origin)
64+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
65+
| |
66+
| invalid use of NULL pointer
67+
| inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:39:14
68+
|
69+
::: $DIR/offset_from_ub.rs:36:1
70+
|
71+
LL | / pub const OFFSET_FROM_NULL: isize = {
72+
LL | |
73+
LL | | let ptr = 0 as *const u8;
74+
LL | | unsafe { ptr.offset_from(ptr) }
75+
LL | | };
76+
| |__-
77+
78+
error: any use of this value will cause an error
79+
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
80+
|
81+
LL | intrinsics::ptr_offset_from(self, origin)
82+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
83+
| |
84+
| a memory access tried to interpret some bytes as a pointer
85+
| inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:46:14
86+
|
87+
::: $DIR/offset_from_ub.rs:42:1
88+
|
89+
LL | / pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC
90+
LL | |
91+
LL | | let ptr1 = 8 as *const u8;
92+
LL | | let ptr2 = 16 as *const u8;
93+
LL | | unsafe { ptr2.offset_from(ptr1) }
5794
LL | | };
5895
| |__-
5996

60-
error: aborting due to 3 previous errors
97+
error: aborting due to 5 previous errors
6198

0 commit comments

Comments
 (0)