Skip to content

Commit 02b2232

Browse files
committed
Make sure the initialization of constrained int range newtypes is unsafe
1 parent cc3470c commit 02b2232

File tree

9 files changed

+169
-12
lines changed

9 files changed

+169
-12
lines changed

src/libcore/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
#![feature(never_type)]
9494
#![feature(nll)]
9595
#![feature(exhaustive_patterns)]
96+
#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))]
9697
#![feature(no_core)]
9798
#![feature(on_unimplemented)]
9899
#![feature(optin_builtin_traits)]

src/libcore/nonzero.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,18 @@ use ops::{CoerceUnsized, DispatchFromDyn};
1515
/// A wrapper type for raw pointers and integers that will never be
1616
/// NULL or 0 that might allow certain optimizations.
1717
#[rustc_layout_scalar_valid_range_start(1)]
18-
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
18+
#[derive(Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
1919
#[repr(transparent)]
2020
pub(crate) struct NonZero<T>(pub(crate) T);
2121

22+
// Do not call `T::clone` as theoretically it could turn the field into `0`
23+
// invalidating `NonZero`'s invariant.
24+
impl<T: Copy> Clone for NonZero<T> {
25+
fn clone(&self) -> Self {
26+
unsafe { NonZero(self.0) }
27+
}
28+
}
29+
2230
impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
2331

2432
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}

src/libcore/num/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", st
7070
#[stable(feature = "nonzero", since = "1.28.0")]
7171
#[inline]
7272
pub const unsafe fn new_unchecked(n: $Int) -> Self {
73-
$Ty(NonZero(n))
73+
$Ty(unsafe { NonZero(n) })
7474
}
7575

7676
/// Create a non-zero if the given value is not zero.
7777
#[stable(feature = "nonzero", since = "1.28.0")]
7878
#[inline]
7979
pub fn new(n: $Int) -> Option<Self> {
8080
if n != 0 {
81-
Some($Ty(NonZero(n)))
81+
Some($Ty(unsafe { NonZero(n) }))
8282
} else {
8383
None
8484
}

src/libcore/ptr.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2759,7 +2759,7 @@ impl<T: ?Sized> Unique<T> {
27592759
/// Creates a new `Unique` if `ptr` is non-null.
27602760
pub fn new(ptr: *mut T) -> Option<Self> {
27612761
if !ptr.is_null() {
2762-
Some(Unique { pointer: NonZero(ptr as _), _marker: PhantomData })
2762+
Some(Unique { pointer: unsafe { NonZero(ptr as _) }, _marker: PhantomData })
27632763
} else {
27642764
None
27652765
}
@@ -2815,14 +2815,14 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> {
28152815
#[unstable(feature = "ptr_internals", issue = "0")]
28162816
impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> {
28172817
fn from(reference: &'a mut T) -> Self {
2818-
Unique { pointer: NonZero(reference as _), _marker: PhantomData }
2818+
Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData }
28192819
}
28202820
}
28212821

28222822
#[unstable(feature = "ptr_internals", issue = "0")]
28232823
impl<'a, T: ?Sized> From<&'a T> for Unique<T> {
28242824
fn from(reference: &'a T) -> Self {
2825-
Unique { pointer: NonZero(reference as _), _marker: PhantomData }
2825+
Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData }
28262826
}
28272827
}
28282828

@@ -2895,15 +2895,15 @@ impl<T: ?Sized> NonNull<T> {
28952895
#[stable(feature = "nonnull", since = "1.25.0")]
28962896
#[inline]
28972897
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
2898-
NonNull { pointer: NonZero(ptr as _) }
2898+
NonNull { pointer: unsafe { NonZero(ptr as _) } }
28992899
}
29002900

29012901
/// Creates a new `NonNull` if `ptr` is non-null.
29022902
#[stable(feature = "nonnull", since = "1.25.0")]
29032903
#[inline]
29042904
pub fn new(ptr: *mut T) -> Option<Self> {
29052905
if !ptr.is_null() {
2906-
Some(NonNull { pointer: NonZero(ptr as _) })
2906+
Some(NonNull { pointer: unsafe { NonZero(ptr as _) } })
29072907
} else {
29082908
None
29092909
}
@@ -3025,14 +3025,14 @@ impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
30253025
impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
30263026
#[inline]
30273027
fn from(reference: &'a mut T) -> Self {
3028-
NonNull { pointer: NonZero(reference as _) }
3028+
NonNull { pointer: unsafe { NonZero(reference as _) } }
30293029
}
30303030
}
30313031

30323032
#[stable(feature = "nonnull", since = "1.25.0")]
30333033
impl<'a, T: ?Sized> From<&'a T> for NonNull<T> {
30343034
#[inline]
30353035
fn from(reference: &'a T) -> Self {
3036-
NonNull { pointer: NonZero(reference as _) }
3036+
NonNull { pointer: unsafe { NonZero(reference as _) } }
30373037
}
30383038
}

src/librustc_mir/transform/check_unsafety.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
2424
use syntax::ast;
2525
use syntax::symbol::Symbol;
2626

27+
use std::ops::Bound;
28+
2729
use util;
2830

2931
pub struct UnsafetyChecker<'a, 'tcx: 'a> {
@@ -136,8 +138,18 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
136138
if let &Rvalue::Aggregate(box ref aggregate, _) = rvalue {
137139
match aggregate {
138140
&AggregateKind::Array(..) |
139-
&AggregateKind::Tuple |
140-
&AggregateKind::Adt(..) => {}
141+
&AggregateKind::Tuple => {}
142+
&AggregateKind::Adt(ref def, ..) => {
143+
match self.tcx.layout_scalar_valid_range(def.did) {
144+
(Bound::Unbounded, Bound::Unbounded) => {},
145+
_ => self.require_unsafe(
146+
"initializing type with `rustc_layout_scalar_valid_range` attr",
147+
"initializing `NonZero` with a `0` violates layout constraints \
148+
and is undefined behavior",
149+
UnsafetyViolationKind::MinConstFn,
150+
),
151+
}
152+
}
141153
&AggregateKind::Closure(def_id, _) |
142154
&AggregateKind::Generator(def_id, _, _) => {
143155
let UnsafetyCheckResult {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![unstable(feature = "humans",
12+
reason = "who ever let humans program computers,
13+
we're apparently really bad at it",
14+
issue = "0")]
15+
16+
#![feature(rustc_const_unstable, const_fn, foo, foo2)]
17+
#![feature(min_const_unsafe_fn)]
18+
#![feature(staged_api)]
19+
20+
#[stable(feature = "rust1", since = "1.0.0")]
21+
#[rustc_const_unstable(feature="foo")]
22+
const unsafe fn foo() -> u32 { 42 }
23+
24+
#[stable(feature = "rust1", since = "1.0.0")]
25+
// can't call non-min_const_fn
26+
const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
27+
28+
#[unstable(feature = "rust1", issue="0")]
29+
const unsafe fn foo2() -> u32 { 42 }
30+
31+
#[stable(feature = "rust1", since = "1.0.0")]
32+
// can't call non-min_const_fn
33+
const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
34+
35+
#[stable(feature = "rust1", since = "1.0.0")]
36+
// conformity is required, even with `const_fn` feature gate
37+
const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
38+
39+
// check whether this function cannot be called even with the feature gate active
40+
#[unstable(feature = "foo2", issue="0")]
41+
const unsafe fn foo2_gated() -> u32 { 42 }
42+
43+
#[stable(feature = "rust1", since = "1.0.0")]
44+
// can't call non-min_const_fn
45+
const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
46+
47+
fn main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: can only call other `min_const_fn` within a `min_const_fn`
2+
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:26:41
3+
|
4+
LL | const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
5+
| ^^^^^
6+
7+
error: can only call other `min_const_fn` within a `min_const_fn`
8+
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:42
9+
|
10+
LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
11+
| ^^^^^^
12+
13+
error: only int, `bool` and `char` operations are stable in const fn
14+
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:37:33
15+
|
16+
LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
17+
| ^^^^^^^^^^^^^
18+
19+
error: can only call other `min_const_fn` within a `min_const_fn`
20+
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:45:48
21+
|
22+
LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
23+
| ^^^^^^^^^^^^
24+
25+
error: aborting due to 4 previous errors
26+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![unstable(feature = "humans",
12+
reason = "who ever let humans program computers,
13+
we're apparently really bad at it",
14+
issue = "0")]
15+
16+
#![feature(rustc_const_unstable, const_fn, foo, foo2)]
17+
#![feature(min_const_unsafe_fn)]
18+
#![feature(staged_api)]
19+
20+
#[stable(feature = "rust1", since = "1.0.0")]
21+
#[rustc_const_unstable(feature="foo")]
22+
const fn foo() -> u32 { 42 }
23+
24+
#[stable(feature = "rust1", since = "1.0.0")]
25+
// can't call non-min_const_fn
26+
const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
27+
28+
#[unstable(feature = "rust1", issue="0")]
29+
const fn foo2() -> u32 { 42 }
30+
31+
#[stable(feature = "rust1", since = "1.0.0")]
32+
// can't call non-min_const_fn
33+
const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
34+
35+
// check whether this function cannot be called even with the feature gate active
36+
#[unstable(feature = "foo2", issue="0")]
37+
const fn foo2_gated() -> u32 { 42 }
38+
39+
#[stable(feature = "rust1", since = "1.0.0")]
40+
// can't call non-min_const_fn
41+
const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
42+
43+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: can only call other `min_const_fn` within a `min_const_fn`
2+
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:26:32
3+
|
4+
LL | const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
5+
| ^^^^^
6+
7+
error: can only call other `min_const_fn` within a `min_const_fn`
8+
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:33
9+
|
10+
LL | const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
11+
| ^^^^^^
12+
13+
error: can only call other `min_const_fn` within a `min_const_fn`
14+
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:41:39
15+
|
16+
LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
17+
| ^^^^^^^^^^^^
18+
19+
error: aborting due to 3 previous errors
20+

0 commit comments

Comments
 (0)