diff options
| author | bors <bors@rust-lang.org> | 2014-03-25 03:01:48 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-03-25 03:01:48 -0700 |
| commit | 5d5634ace087addc6f1d09b55643f97162a4f031 (patch) | |
| tree | aa844738286fa1c64872a58625a6db339104d9fc | |
| parent | b1091c3141f2285fa9620c9e4df3fb86d911c5f6 (diff) | |
| parent | 9021a3f988ca134f52ca8b7d6a06952d46a38722 (diff) | |
| download | rust-5d5634ace087addc6f1d09b55643f97162a4f031.tar.gz rust-5d5634ace087addc6f1d09b55643f97162a4f031.zip | |
auto merge of #13083 : FlaPer87/rust/issue-13005-borrow-unsafe-static, r=nikomatsakis
It was possible to borrow unsafe static items in static initializers. This patch implements a small `Visitor` that walks static initializer's expressions and checks borrows aliasability. Fixes #13005 cc @nikomatsakis r?
| -rw-r--r-- | src/librustc/middle/borrowck/gather_loans/mod.rs | 167 | ||||
| -rw-r--r-- | src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs | 7 |
2 files changed, 100 insertions, 74 deletions
diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index be86d387b20..a6409131bed 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -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; @@ -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 } @@ -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 { @@ -948,3 +926,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, ()); +} diff --git a/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs b/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs index c790a040a91..9939fc79190 100644 --- a/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs +++ b/src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs @@ -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; |
