Make sure the initialization of constrained int range newtypes is unsafe

This commit is contained in:
Oliver Scherer 2018-11-03 13:03:05 +01:00
parent cc3470ce3b
commit 02b22323f1
9 changed files with 169 additions and 12 deletions

View 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)]

View file

@ -15,10 +15,18 @@ use ops::{CoerceUnsized, DispatchFromDyn};
/// 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> {}

View file

@ -70,7 +70,7 @@ assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", st
#[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 @@ assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", st
#[inline]
pub fn new(n: $Int) -> Option<Self> {
if n != 0 {
Some($Ty(NonZero(n)))
Some($Ty(unsafe { NonZero(n) }))
} else {
None
}

View 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 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> {
#[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 @@ impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
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 @@ impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
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 _) } }
}
}

View file

@ -24,6 +24,8 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
use syntax::ast;
use syntax::symbol::Symbol;
use std::ops::Bound;
use util;
pub struct UnsafetyChecker<'a, 'tcx: 'a> {
@ -136,8 +138,18 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
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 {

View file

@ -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() {}

View file

@ -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

View file

@ -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() {}

View file

@ -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