Forbid borrow of static items with unsafe interior

This commit is contained in:
Flavio Percoco 2014-03-13 01:02:31 +01:00
parent 69ccd807da
commit ff1c49fa54
6 changed files with 114 additions and 36 deletions

View file

@ -518,11 +518,11 @@ fn check_for_aliasability_violation(this: &CheckLoanCtxt,
expr: &ast::Expr,
cmt: mc::cmt)
-> bool {
match cmt.freely_aliasable() {
match cmt.freely_aliasable(this.tcx()) {
None => {
return true;
}
Some(mc::AliasableStaticMut) => {
Some(mc::AliasableStaticMut(..)) => {
return true;
}
Some(cause) => {

View file

@ -175,9 +175,9 @@ pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &ast::E
move_data: MoveData::new()
};
// FIXME #13005 This should also walk the
// expression.
match expr.node {
// Just visit the expression if the
// item is taking an address.
ast::ExprAddrOf(..) => {
glcx.visit_expr(expr, ());
}
@ -686,34 +686,45 @@ fn check_aliasability(bccx: &BorrowckCtxt,
-> Result<(),()> {
//! Implements the A-* rules in doc.rs.
match req_kind {
ty::ImmBorrow => {
match (cmt.freely_aliasable(bccx.tcx), req_kind) {
(None, _) => {
/* Uniquely accessible path -- OK for `&` and `&mut` */
Ok(())
}
ty::UniqueImmBorrow | ty::MutBorrow => {
// Check for those cases where we cannot control
// the aliasing and make sure that we are not
// being asked to.
match cmt.freely_aliasable() {
None => {
(Some(mc::AliasableStatic(safety)), ty::ImmBorrow) => {
// Borrow of an immutable static item:
match safety {
mc::InteriorUnsafe => {
// If the static item contains an Unsafe<T>, it has interior mutability.
// In such cases, we cannot permit it to be borrowed, because the
// static item resides in immutable memory and mutating it would
// cause segfaults.
bccx.tcx.sess.span_err(borrow_span,
format!("borrow of immutable static items with \
unsafe interior is not allowed"));
Err(())
}
mc::InteriorSafe => {
// Immutable static can be borrowed, no problem.
Ok(())
}
Some(mc::AliasableStaticMut) => {
// This is nasty, but we ignore the
// aliasing rules if the data is based in
// a `static mut`, since those are always
// unsafe. At your own peril and all that.
Ok(())
}
Some(alias_cause) => {
bccx.report_aliasability_violation(
}
}
(Some(mc::AliasableStaticMut(..)), _) => {
// Even touching a static mut is considered unsafe. We assume the
// user knows what they're doing in these cases.
Ok(())
}
(Some(alias_cause), ty::UniqueImmBorrow) |
(Some(alias_cause), ty::MutBorrow) => {
bccx.report_aliasability_violation(
borrow_span,
BorrowViolation(loan_cause),
alias_cause);
Err(())
}
}
Err(())
}
(_, _) => {
Ok(())
}
}
}

View file

@ -130,9 +130,10 @@ fn borrowck_item(this: &mut BorrowckCtxt, item: &ast::Item) {
ast::ItemStatic(_, _, ex) => {
gather_loans::gather_loans_in_static_initializer(this, ex);
}
_ => {}
_ => {
visit::walk_item(this, item, ());
}
}
visit::walk_item(this, item, ());
}
fn borrowck_fn(this: &mut BorrowckCtxt,
@ -733,8 +734,8 @@ pub fn report_aliasability_violation(&self,
span,
format!("{} in an aliasable location", prefix));
}
mc::AliasableStatic |
mc::AliasableStaticMut => {
mc::AliasableStatic(..) |
mc::AliasableStaticMut(..) => {
self.tcx.sess.span_err(
span,
format!("{} in a static location", prefix));

View file

@ -1222,12 +1222,17 @@ pub fn field_mutbl(tcx: &ty::ctxt,
return None;
}
pub enum InteriorSafety {
InteriorUnsafe,
InteriorSafe
}
pub enum AliasableReason {
AliasableManaged,
AliasableBorrowed,
AliasableOther,
AliasableStatic,
AliasableStaticMut,
AliasableStatic(InteriorSafety),
AliasableStaticMut(InteriorSafety),
}
impl cmt_ {
@ -1257,7 +1262,7 @@ pub fn guarantor(self) -> cmt {
}
}
pub fn freely_aliasable(&self) -> Option<AliasableReason> {
pub fn freely_aliasable(&self, ctxt: &ty::ctxt) -> Option<AliasableReason> {
/*!
* Returns `Some(_)` if this lvalue represents a freely aliasable
* pointer type.
@ -1275,7 +1280,7 @@ pub fn freely_aliasable(&self) -> Option<AliasableReason> {
cat_interior(b, _) |
cat_discr(b, _) => {
// Aliasability depends on base cmt
b.freely_aliasable()
b.freely_aliasable(ctxt)
}
cat_copied_upvar(CopiedUpvar {onceness: ast::Once, ..}) |
@ -1292,10 +1297,16 @@ pub fn freely_aliasable(&self) -> Option<AliasableReason> {
}
cat_static_item(..) => {
if self.mutbl.is_mutable() {
Some(AliasableStaticMut)
let int_safe = if ty::type_interior_is_unsafe(ctxt, self.ty) {
InteriorUnsafe
} else {
Some(AliasableStatic)
InteriorSafe
};
if self.mutbl.is_mutable() {
Some(AliasableStaticMut(int_safe))
} else {
Some(AliasableStatic(int_safe))
}
}

View file

@ -1996,6 +1996,10 @@ pub fn is_pod(&self, _: &ctxt) -> bool {
!self.intersects(TC::Nonpod)
}
pub fn interior_unsafe(&self) -> bool {
self.intersects(TC::InteriorUnsafe)
}
pub fn moves_by_default(&self, _: &ctxt) -> bool {
self.intersects(TC::Moves)
}
@ -2092,6 +2096,10 @@ pub fn type_is_freezable(cx: &ctxt, t: ty::t) -> bool {
type_contents(cx, t).is_freezable(cx)
}
pub fn type_interior_is_unsafe(cx: &ctxt, t: ty::t) -> bool {
type_contents(cx, t).interior_unsafe()
}
pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
let ty_id = type_id(ty);

View file

@ -0,0 +1,47 @@
// Copyright 2014 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.
// Verify that it is not possible to take the address of
// static items with usnafe interior.
use std::kinds::marker;
use std::ty::Unsafe;
struct MyUnsafe<T> {
value: Unsafe<T>
}
impl<T> MyUnsafe<T> {
fn forbidden(&self) {}
}
enum UnsafeEnum<T> {
VariantSafe,
VariantUnsafe(Unsafe<T>)
}
static STATIC1: UnsafeEnum<int> = VariantSafe;
static STATIC2: Unsafe<int> = Unsafe{value: 1, marker1: marker::InvariantType};
static STATIC3: MyUnsafe<int> = MyUnsafe{value: STATIC2};
static STATIC4: &'static Unsafe<int> = &'static STATIC2;
//~^ ERROR borrow of immutable static items with unsafe interior is not allowed
fn main() {
let a = &STATIC1;
//~^ ERROR borrow of immutable static items with unsafe interior is not allowed
STATIC3.forbidden()
//~^ ERROR borrow of immutable static items with unsafe interior is not allowed
}