mirror of
https://github.com/rust-lang/rust
synced 2024-10-01 06:14:33 +00:00
rustc: Completely forbid borrows of unsafe statics
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
This commit is contained in:
parent
5e8e1b515a
commit
9021a3f988
|
@ -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, ());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue