]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Completely forbid borrows of unsafe statics
authorFlavio Percoco <flaper87@gmail.com>
Sat, 22 Mar 2014 18:49:25 +0000 (19:49 +0100)
committerFlavio Percoco <flaper87@gmail.com>
Mon, 24 Mar 2014 17:04:10 +0000 (18:04 +0100)
Summary:
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

Test Plan: make check

Differential Revision: http://phabricator.octayn.net/D2

src/librustc/middle/borrowck/gather_loans/mod.rs
src/test/compile-fail/borrowck-forbid-static-unsafe-interior.rs

index 8ecac0a60bede1cc24d39de84af1d7346080faba..efe9ebff61a420f6f800470e85b3838c92c4d49d 100644 (file)
@@ -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 @@ fn check_mutability(bccx: &BorrowckCtxt,
                 }
             }
         }
-
-        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 {
@@ -951,3 +929,44 @@ pub fn pat_is_binding(&self, pat: &ast::Pat) -> bool {
         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, ());
+}
index c790a040a91a4be332c9240b52994022f0509af3..9939fc791907d0fb166247c34f1b86e7563d91aa 100644 (file)
@@ -35,6 +35,13 @@ enum UnsafeEnum<T> {
 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;