Skip to content

Commit 3cd1dc1

Browse files
authored
Rollup merge of rust-lang#94270 - RalfJung:fn-ptrs, r=oli-obk
Miri: relax fn ptr check As discussed in rust-lang/unsafe-code-guidelines#72 (comment), the function pointer check done by Miri is currently overeager: contrary to our usual principle of only checking rather uncontroversial validity invariants, we actually check that the pointer points to a real function. So, this relaxes the check to what the validity invariant probably will be (and what the reference already says it is): the function pointer must be non-null, and that's it. The check that CTFE does on the final value of a constant is unchanged -- CTFE recurses through references, so it makes some sense to also recurse through function pointers. We might still want to relax this in the future, but that would be a separate change. r? `@oli-obk`
2 parents 8a42e3d + 182d335 commit 3cd1dc1

File tree

4 files changed

+110
-31
lines changed

4 files changed

+110
-31
lines changed

compiler/rustc_const_eval/src/interpret/validity.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -567,22 +567,27 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
567567
}
568568
ty::FnPtr(_sig) => {
569569
let value = try_validation!(
570-
self.ecx.read_immediate(value),
570+
self.ecx.read_scalar(value).and_then(|v| v.check_init()),
571571
self.path,
572572
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
573+
err_ub!(InvalidUninitBytes(None)) => { "uninitialized bytes" } expected { "a proper pointer or integer value" },
573574
);
574-
// Make sure we print a `ScalarMaybeUninit` (and not an `ImmTy`) in the error
575-
// message below.
576-
let value = value.to_scalar_or_uninit();
577-
let _fn = try_validation!(
578-
value.check_init().and_then(|ptr| self.ecx.memory.get_fn(self.ecx.scalar_to_ptr(ptr))),
579-
self.path,
580-
err_ub!(DanglingIntPointer(..)) |
581-
err_ub!(InvalidFunctionPointer(..)) |
582-
err_ub!(InvalidUninitBytes(None)) =>
583-
{ "{:x}", value } expected { "a function pointer" },
584-
);
585-
// FIXME: Check if the signature matches
575+
let ptr = self.ecx.scalar_to_ptr(value);
576+
// Ensure the pointer is non-null.
577+
if self.ecx.memory.ptr_may_be_null(ptr) {
578+
throw_validation_failure!(self.path, { "a potentially null function pointer" });
579+
}
580+
// If we check references recursively, also check that this points to a function.
581+
if let Some(_) = self.ref_tracking {
582+
let _fn = try_validation!(
583+
self.ecx.memory.get_fn(ptr),
584+
self.path,
585+
err_ub!(DanglingIntPointer(..)) |
586+
err_ub!(InvalidFunctionPointer(..)) =>
587+
{ "{:x}", value } expected { "a function pointer" },
588+
);
589+
// FIXME: Check if the signature matches
590+
}
586591
Ok(true)
587592
}
588593
ty::Never => throw_validation_failure!(self.path, { "a value of the never type `!`" }),

src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr

+42-9
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
4343
}
4444

4545
error[E0080]: it is undefined behavior to use this value
46-
--> $DIR/ub-ref-ptr.rs:30:1
46+
--> $DIR/ub-ref-ptr.rs:31:1
4747
|
4848
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
4949
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc15, but expected initialized plain (non-pointer) bytes
@@ -54,7 +54,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
5454
}
5555

5656
error[E0080]: it is undefined behavior to use this value
57-
--> $DIR/ub-ref-ptr.rs:33:1
57+
--> $DIR/ub-ref-ptr.rs:34:1
5858
|
5959
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
6060
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
@@ -65,7 +65,7 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
6565
}
6666

6767
error[E0080]: it is undefined behavior to use this value
68-
--> $DIR/ub-ref-ptr.rs:36:1
68+
--> $DIR/ub-ref-ptr.rs:37:1
6969
|
7070
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
7171
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
@@ -76,7 +76,7 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
7676
}
7777

7878
error[E0080]: it is undefined behavior to use this value
79-
--> $DIR/ub-ref-ptr.rs:39:1
79+
--> $DIR/ub-ref-ptr.rs:40:1
8080
|
8181
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
8282
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x539 is unallocated)
@@ -87,7 +87,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
8787
}
8888

8989
error[E0080]: it is undefined behavior to use this value
90-
--> $DIR/ub-ref-ptr.rs:42:1
90+
--> $DIR/ub-ref-ptr.rs:43:1
9191
|
9292
LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
9393
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (address 0x539 is unallocated)
@@ -98,7 +98,7 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
9898
}
9999

100100
error[E0080]: it is undefined behavior to use this value
101-
--> $DIR/ub-ref-ptr.rs:45:1
101+
--> $DIR/ub-ref-ptr.rs:46:1
102102
|
103103
LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
104104
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized raw pointer
@@ -109,16 +109,49 @@ LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
109109
}
110110

111111
error[E0080]: it is undefined behavior to use this value
112-
--> $DIR/ub-ref-ptr.rs:47:1
112+
--> $DIR/ub-ref-ptr.rs:49:1
113+
|
114+
LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
115+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a potentially null function pointer
116+
|
117+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
118+
= note: the raw bytes of the constant (size: 4, align: 4) {
119+
00 00 00 00 │ ....
120+
}
121+
122+
error[E0080]: it is undefined behavior to use this value
123+
--> $DIR/ub-ref-ptr.rs:51:1
113124
|
114125
LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
115-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a function pointer
126+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value
116127
|
117128
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
118129
= note: the raw bytes of the constant (size: 4, align: 4) {
119130
__ __ __ __ │ ░░░░
120131
}
121132

122-
error: aborting due to 11 previous errors
133+
error[E0080]: it is undefined behavior to use this value
134+
--> $DIR/ub-ref-ptr.rs:53:1
135+
|
136+
LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
137+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x0000000d, but expected a function pointer
138+
|
139+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
140+
= note: the raw bytes of the constant (size: 4, align: 4) {
141+
0d 00 00 00 │ ....
142+
}
143+
144+
error[E0080]: it is undefined behavior to use this value
145+
--> $DIR/ub-ref-ptr.rs:55:1
146+
|
147+
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
148+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc41, but expected a function pointer
149+
|
150+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
151+
= note: the raw bytes of the constant (size: 4, align: 4) {
152+
╾─alloc41─╼ │ ╾──╼
153+
}
154+
155+
error: aborting due to 14 previous errors
123156

124157
For more information about this error, try `rustc --explain E0080`.

src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr

+42-9
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
4343
}
4444

4545
error[E0080]: it is undefined behavior to use this value
46-
--> $DIR/ub-ref-ptr.rs:30:1
46+
--> $DIR/ub-ref-ptr.rs:31:1
4747
|
4848
LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
4949
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc15, but expected initialized plain (non-pointer) bytes
@@ -54,7 +54,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
5454
}
5555

5656
error[E0080]: it is undefined behavior to use this value
57-
--> $DIR/ub-ref-ptr.rs:33:1
57+
--> $DIR/ub-ref-ptr.rs:34:1
5858
|
5959
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
6060
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
@@ -65,7 +65,7 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
6565
}
6666

6767
error[E0080]: it is undefined behavior to use this value
68-
--> $DIR/ub-ref-ptr.rs:36:1
68+
--> $DIR/ub-ref-ptr.rs:37:1
6969
|
7070
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
7171
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
@@ -76,7 +76,7 @@ LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[us
7676
}
7777

7878
error[E0080]: it is undefined behavior to use this value
79-
--> $DIR/ub-ref-ptr.rs:39:1
79+
--> $DIR/ub-ref-ptr.rs:40:1
8080
|
8181
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
8282
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x539 is unallocated)
@@ -87,7 +87,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
8787
}
8888

8989
error[E0080]: it is undefined behavior to use this value
90-
--> $DIR/ub-ref-ptr.rs:42:1
90+
--> $DIR/ub-ref-ptr.rs:43:1
9191
|
9292
LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
9393
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (address 0x539 is unallocated)
@@ -98,7 +98,7 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
9898
}
9999

100100
error[E0080]: it is undefined behavior to use this value
101-
--> $DIR/ub-ref-ptr.rs:45:1
101+
--> $DIR/ub-ref-ptr.rs:46:1
102102
|
103103
LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
104104
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized raw pointer
@@ -109,16 +109,49 @@ LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
109109
}
110110

111111
error[E0080]: it is undefined behavior to use this value
112-
--> $DIR/ub-ref-ptr.rs:47:1
112+
--> $DIR/ub-ref-ptr.rs:49:1
113+
|
114+
LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
115+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a potentially null function pointer
116+
|
117+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
118+
= note: the raw bytes of the constant (size: 8, align: 8) {
119+
00 00 00 00 00 00 00 00 │ ........
120+
}
121+
122+
error[E0080]: it is undefined behavior to use this value
123+
--> $DIR/ub-ref-ptr.rs:51:1
113124
|
114125
LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
115-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a function pointer
126+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value
116127
|
117128
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
118129
= note: the raw bytes of the constant (size: 8, align: 8) {
119130
__ __ __ __ __ __ __ __ │ ░░░░░░░░
120131
}
121132

122-
error: aborting due to 11 previous errors
133+
error[E0080]: it is undefined behavior to use this value
134+
--> $DIR/ub-ref-ptr.rs:53:1
135+
|
136+
LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
137+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x000000000000000d, but expected a function pointer
138+
|
139+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
140+
= note: the raw bytes of the constant (size: 8, align: 8) {
141+
0d 00 00 00 00 00 00 00 │ ........
142+
}
143+
144+
error[E0080]: it is undefined behavior to use this value
145+
--> $DIR/ub-ref-ptr.rs:55:1
146+
|
147+
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
148+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc41, but expected a function pointer
149+
|
150+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
151+
= note: the raw bytes of the constant (size: 8, align: 8) {
152+
╾───────alloc41───────╼ │ ╾──────╼
153+
}
154+
155+
error: aborting due to 14 previous errors
123156

124157
For more information about this error, try `rustc --explain E0080`.

src/test/ui/consts/const-eval/ub-ref-ptr.rs

+8
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const NULL: &u16 = unsafe { mem::transmute(0usize) };
2424
const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
2525
//~^ ERROR it is undefined behavior to use this value
2626

27+
2728
// It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`,
2829
// but that would fail to compile; so we ended up breaking user code that would
2930
// have worked fine had we not promoted.
@@ -44,7 +45,14 @@ const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) };
4445

4546
const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init };
4647
//~^ ERROR it is undefined behavior to use this value
48+
49+
const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
50+
//~^ ERROR it is undefined behavior to use this value
4751
const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init };
4852
//~^ ERROR it is undefined behavior to use this value
53+
const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
54+
//~^ ERROR it is undefined behavior to use this value
55+
const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
56+
//~^ ERROR it is undefined behavior to use this value
4957

5058
fn main() {}

0 commit comments

Comments
 (0)