summary refs log tree commit diff
path: root/compiler/rustc_const_eval/src
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-02-24 07:48:06 +0100
committerGitHub <noreply@github.com>2022-02-24 07:48:06 +0100
commit3cd1dc1d6ec80efa2cff237d8494d825ab983da6 (patch)
treea409691506547c78ce7f4924122860d931068835 /compiler/rustc_const_eval/src
parent8a42e3da0bae5b25d42c0eea29884b31a41215e1 (diff)
parent182d335870265a102c0f6467db65b5e59bd97e24 (diff)
downloadrust-3cd1dc1d6ec80efa2cff237d8494d825ab983da6.tar.gz
rust-3cd1dc1d6ec80efa2cff237d8494d825ab983da6.zip
Rollup merge of #94270 - RalfJung:fn-ptrs, r=oli-obk
Miri: relax fn ptr check

As discussed in https://github.com/rust-lang/unsafe-code-guidelines/issues/72#issuecomment-1025407536, 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`
Diffstat (limited to 'compiler/rustc_const_eval/src')
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs31
1 files changed, 18 insertions, 13 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 54e29299e6c..0bf86d52080 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -567,22 +567,27 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
             }
             ty::FnPtr(_sig) => {
                 let value = try_validation!(
-                    self.ecx.read_immediate(value),
+                    self.ecx.read_scalar(value).and_then(|v| v.check_init()),
                     self.path,
                     err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
+                    err_ub!(InvalidUninitBytes(None)) => { "uninitialized bytes" } expected { "a proper pointer or integer value" },
                 );
-                // Make sure we print a `ScalarMaybeUninit` (and not an `ImmTy`) in the error
-                // message below.
-                let value = value.to_scalar_or_uninit();
-                let _fn = try_validation!(
-                    value.check_init().and_then(|ptr| self.ecx.memory.get_fn(self.ecx.scalar_to_ptr(ptr))),
-                    self.path,
-                    err_ub!(DanglingIntPointer(..)) |
-                    err_ub!(InvalidFunctionPointer(..)) |
-                    err_ub!(InvalidUninitBytes(None)) =>
-                        { "{:x}", value } expected { "a function pointer" },
-                );
-                // FIXME: Check if the signature matches
+                let ptr = self.ecx.scalar_to_ptr(value);
+                // Ensure the pointer is non-null.
+                if self.ecx.memory.ptr_may_be_null(ptr) {
+                    throw_validation_failure!(self.path, { "a potentially null function pointer" });
+                }
+                // If we check references recursively, also check that this points to a function.
+                if let Some(_) = self.ref_tracking {
+                    let _fn = try_validation!(
+                        self.ecx.memory.get_fn(ptr),
+                        self.path,
+                        err_ub!(DanglingIntPointer(..)) |
+                        err_ub!(InvalidFunctionPointer(..)) =>
+                            { "{:x}", value } expected { "a function pointer" },
+                    );
+                    // FIXME: Check if the signature matches
+                }
                 Ok(true)
             }
             ty::Never => throw_validation_failure!(self.path, { "a value of the never type `!`" }),