]> git.lizzy.rs Git - rust.git/commitdiff
Make sure the initialization of constrained int range newtypes is unsafe
authorOliver Scherer <github35764891676564198441@oli-obk.de>
Sat, 3 Nov 2018 12:03:05 +0000 (13:03 +0100)
committerOliver Scherer <github35764891676564198441@oli-obk.de>
Tue, 4 Dec 2018 09:17:36 +0000 (10:17 +0100)
src/libcore/lib.rs
src/libcore/nonzero.rs
src/libcore/num/mod.rs
src/libcore/ptr.rs
src/librustc_mir/transform/check_unsafety.rs
src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs [new file with mode: 0644]
src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr [new file with mode: 0644]

index 726e891df0ccf2f4e4c63d4dee08121594785f5d..d070160609d291a771283b9edd6229316c1b58b0 100644 (file)
@@ -93,6 +93,7 @@
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(exhaustive_patterns)]
+#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))]
 #![feature(no_core)]
 #![feature(on_unimplemented)]
 #![feature(optin_builtin_traits)]
index 436cd1fc0572837e408407e9d0bb7b310eea92b2..22d93a5301efa870f47d7cb2a0384c178677ebf1 100644 (file)
 /// A wrapper type for raw pointers and integers that will never be
 /// NULL or 0 that might allow certain optimizations.
 #[rustc_layout_scalar_valid_range_start(1)]
-#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
 #[repr(transparent)]
 pub(crate) struct NonZero<T>(pub(crate) T);
 
+// Do not call `T::clone` as theoretically it could turn the field into `0`
+// invalidating `NonZero`'s invariant.
+impl<T: Copy> Clone for NonZero<T> {
+    fn clone(&self) -> Self {
+        unsafe { NonZero(self.0) }
+    }
+}
+
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
 
 impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}
index 805be431328e208bd7f0be755c91a7ee50618f65..7f5d596b220b9e99fdf604d86467a7d28c51f351 100644 (file)
@@ -70,7 +70,7 @@ impl $Ty {
                 #[stable(feature = "nonzero", since = "1.28.0")]
                 #[inline]
                 pub const unsafe fn new_unchecked(n: $Int) -> Self {
-                    $Ty(NonZero(n))
+                    $Ty(unsafe { NonZero(n) })
                 }
 
                 /// Create a non-zero if the given value is not zero.
@@ -78,7 +78,7 @@ impl $Ty {
                 #[inline]
                 pub fn new(n: $Int) -> Option<Self> {
                     if n != 0 {
-                        Some($Ty(NonZero(n)))
+                        Some($Ty(unsafe { NonZero(n) }))
                     } else {
                         None
                     }
index d3a74ed2a68563e83bfc845546067e9191c2669b..a07c7260f712ce36fac6c53ee5739c517d2f3e56 100644 (file)
@@ -2759,7 +2759,7 @@ impl<T: ?Sized> Unique<T> {
     /// Creates a new `Unique` if `ptr` is non-null.
     pub fn new(ptr: *mut T) -> Option<Self> {
         if !ptr.is_null() {
-            Some(Unique { pointer: NonZero(ptr as _), _marker: PhantomData })
+            Some(Unique { pointer: unsafe { NonZero(ptr as _) }, _marker: PhantomData })
         } else {
             None
         }
@@ -2815,14 +2815,14 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 #[unstable(feature = "ptr_internals", issue = "0")]
 impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> {
     fn from(reference: &'a mut T) -> Self {
-        Unique { pointer: NonZero(reference as _), _marker: PhantomData }
+        Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData }
     }
 }
 
 #[unstable(feature = "ptr_internals", issue = "0")]
 impl<'a, T: ?Sized> From<&'a T> for Unique<T> {
     fn from(reference: &'a T) -> Self {
-        Unique { pointer: NonZero(reference as _), _marker: PhantomData }
+        Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData }
     }
 }
 
@@ -2895,7 +2895,7 @@ impl<T: ?Sized> NonNull<T> {
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[inline]
     pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
-        NonNull { pointer: NonZero(ptr as _) }
+        NonNull { pointer: unsafe { NonZero(ptr as _) } }
     }
 
     /// Creates a new `NonNull` if `ptr` is non-null.
@@ -2903,7 +2903,7 @@ impl<T: ?Sized> NonNull<T> {
     #[inline]
     pub fn new(ptr: *mut T) -> Option<Self> {
         if !ptr.is_null() {
-            Some(NonNull { pointer: NonZero(ptr as _) })
+            Some(NonNull { pointer: unsafe { NonZero(ptr as _) } })
         } else {
             None
         }
@@ -3025,7 +3025,7 @@ fn from(unique: Unique<T>) -> Self {
 impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
     #[inline]
     fn from(reference: &'a mut T) -> Self {
-        NonNull { pointer: NonZero(reference as _) }
+        NonNull { pointer: unsafe { NonZero(reference as _) } }
     }
 }
 
@@ -3033,6 +3033,6 @@ fn from(reference: &'a mut T) -> Self {
 impl<'a, T: ?Sized> From<&'a T> for NonNull<T> {
     #[inline]
     fn from(reference: &'a T) -> Self {
-        NonNull { pointer: NonZero(reference as _) }
+        NonNull { pointer: unsafe { NonZero(reference as _) } }
     }
 }
index 0547e4476cbe448369e2c89aab8c0e8088362cbe..2c80e573749991e38c7e646ce154698088c7a930 100644 (file)
@@ -24,6 +24,8 @@
 use syntax::ast;
 use syntax::symbol::Symbol;
 
+use std::ops::Bound;
+
 use util;
 
 pub struct UnsafetyChecker<'a, 'tcx: 'a> {
@@ -136,8 +138,18 @@ fn visit_rvalue(&mut self,
         if let &Rvalue::Aggregate(box ref aggregate, _) = rvalue {
             match aggregate {
                 &AggregateKind::Array(..) |
-                &AggregateKind::Tuple |
-                &AggregateKind::Adt(..) => {}
+                &AggregateKind::Tuple => {}
+                &AggregateKind::Adt(ref def, ..) => {
+                    match self.tcx.layout_scalar_valid_range(def.did) {
+                        (Bound::Unbounded, Bound::Unbounded) => {},
+                        _ => self.require_unsafe(
+                            "initializing type with `rustc_layout_scalar_valid_range` attr",
+                            "initializing `NonZero` with a `0` violates layout constraints \
+                            and is undefined behavior",
+                            UnsafetyViolationKind::MinConstFn,
+                        ),
+                    }
+                }
                 &AggregateKind::Closure(def_id, _) |
                 &AggregateKind::Generator(def_id, _, _) => {
                     let UnsafetyCheckResult {
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
new file mode 100644 (file)
index 0000000..f559c23
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![unstable(feature = "humans",
+            reason = "who ever let humans program computers,
+            we're apparently really bad at it",
+            issue = "0")]
+
+#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(min_const_unsafe_fn)]
+#![feature(staged_api)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo")]
+const unsafe fn foo() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
+
+#[unstable(feature = "rust1", issue="0")]
+const unsafe fn foo2() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// conformity is required, even with `const_fn` feature gate
+const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
+
+// check whether this function cannot be called even with the feature gate active
+#[unstable(feature = "foo2", issue="0")]
+const unsafe fn foo2_gated() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
+
+fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
new file mode 100644 (file)
index 0000000..37be288
--- /dev/null
@@ -0,0 +1,26 @@
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:26:41
+   |
+LL | const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
+   |                                         ^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:42
+   |
+LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
+   |                                          ^^^^^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:37:33
+   |
+LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
+   |                                 ^^^^^^^^^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:45:48
+   |
+LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
+   |                                                ^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
new file mode 100644 (file)
index 0000000..131bc97
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![unstable(feature = "humans",
+            reason = "who ever let humans program computers,
+            we're apparently really bad at it",
+            issue = "0")]
+
+#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(min_const_unsafe_fn)]
+#![feature(staged_api)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo")]
+const fn foo() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+
+#[unstable(feature = "rust1", issue="0")]
+const fn foo2() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+
+// check whether this function cannot be called even with the feature gate active
+#[unstable(feature = "foo2", issue="0")]
+const fn foo2_gated() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
+
+fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
new file mode 100644 (file)
index 0000000..0b58dc1
--- /dev/null
@@ -0,0 +1,20 @@
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:26:32
+   |
+LL | const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+   |                                ^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:33
+   |
+LL | const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+   |                                 ^^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:41:39
+   |
+LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
+   |                                       ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+