Skip to content

rustc: Completely forbid borrows of unsafe statics #13083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 25, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 93 additions & 74 deletions src/librustc/middle/borrowck/gather_loans/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,29 +161,6 @@ fn gather_loans_in_local(this: &mut GatherLoanCtxt,
visit::walk_local(this, local, ());
}

pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &ast::Expr) {

debug!("gather_loans_in_item(expr={})", expr.repr(bccx.tcx));

let mut glcx = GatherLoanCtxt {
bccx: bccx,
id_range: IdRange::max(),
all_loans: Vec::new(),
item_ub: expr.id,
repeating_ids: vec!(expr.id),
move_data: MoveData::new()
};

// FIXME #13005 This should also walk the
// expression.
match expr.node {
ast::ExprAddrOf(..) => {
glcx.visit_expr(expr, ());
}
_ => {}
}
}

fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
ex: &ast::Expr) {
let bccx = this.bccx;
Expand Down Expand Up @@ -326,6 +303,58 @@ fn with_assignee_loan_path(bccx: &BorrowckCtxt, expr: &ast::Expr, op: |@LoanPath
}
}


/// Implements the A-* rules in doc.rs.
fn check_aliasability(bccx: &BorrowckCtxt,
borrow_span: Span,
loan_cause: LoanCause,
cmt: mc::cmt,
req_kind: ty::BorrowKind)
-> Result<(),()> {

match (cmt.freely_aliasable(bccx.tcx), req_kind) {
(None, _) => {
/* Uniquely accessible path -- OK for `&` and `&mut` */
Ok(())
}
(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(..)), _) => {
// 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(())
}
(_, _) => {
Ok(())
}
}
}

impl<'a> GatherLoanCtxt<'a> {
pub fn tcx(&self) -> &'a ty::ctxt { self.bccx.tcx }

Expand Down Expand Up @@ -676,57 +705,6 @@ impl<'a> GatherLoanCtxt<'a> {
}
}
}

fn check_aliasability(bccx: &BorrowckCtxt,
borrow_span: Span,
loan_cause: LoanCause,
cmt: mc::cmt,
req_kind: ty::BorrowKind)
-> Result<(),()> {
//! Implements the A-* rules in doc.rs.

match (cmt.freely_aliasable(bccx.tcx), req_kind) {
(None, _) => {
/* Uniquely accessible path -- OK for `&` and `&mut` */
Ok(())
}
(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(..)), _) => {
// 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(())
}
(_, _) => {
Ok(())
}
}
}
}

fn restriction_set(&self, req_kind: ty::BorrowKind) -> RestrictionSet {
Expand Down Expand Up @@ -951,3 +929,44 @@ impl<'a> GatherLoanCtxt<'a> {
pat_util::pat_is_binding(self.bccx.tcx.def_map, pat)
}
}

/// Context used while gathering loans on static initializers
///
/// This visitor walks static initializer's expressions and makes
/// sure the loans being taken are sound.
struct StaticInitializerCtxt<'a> {
bccx: &'a BorrowckCtxt<'a>,
id_range: IdRange,
item_ub: ast::NodeId,
}

impl<'a> visit::Visitor<()> for StaticInitializerCtxt<'a> {
fn visit_expr(&mut self, ex: &Expr, _: ()) {
match ex.node {
ast::ExprAddrOf(mutbl, base) => {
let base_cmt = self.bccx.cat_expr(base);
let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
// Check that we don't allow borrows of unsafe static items.
if check_aliasability(self.bccx, ex.span, AddrOf, base_cmt, borrow_kind).is_err() {
return; // reported an error, no sense in reporting more.
}
}
_ => {}
}

visit::walk_expr(self, ex, ());
}
}

pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &ast::Expr) {

debug!("gather_loans_in_static_initializer(expr={})", expr.repr(bccx.tcx));

let mut sicx = StaticInitializerCtxt {
bccx: bccx,
id_range: IdRange::max(),
item_ub: expr.id,
};

sicx.visit_expr(expr, ());
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ 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

struct Wrap<T> {
value: T
}

static UNSAFE: Unsafe<int> = Unsafe{value: 1, marker1: marker::InvariantType};
static WRAPPED_UNSAFE: Wrap<&'static Unsafe<int>> = Wrap { value: &UNSAFE };
//~^ ERROR borrow of immutable static items with unsafe interior is not allowed

fn main() {
let a = &STATIC1;
Expand Down