Skip to content

Commit ee2f001

Browse files
committed
Forbid certain types for static items
- For each *mutable* static item, check that the **type**: - cannot own any value whose type has a dtor - cannot own any values whose type is an owned pointer - For each *immutable* static item, check that the **value**: - does not contain any ~ or box expressions (including ~[1, 2, 3] sort of things) - does not contain a struct literal or call to an enum variant / struct constructor where - the type of the struct/enum has a dtor
1 parent 8784d2f commit ee2f001

File tree

6 files changed

+279
-1
lines changed

6 files changed

+279
-1
lines changed

src/librustc/driver/driver.rs

+3
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ pub fn phase_3_run_analysis_passes(sess: Session,
301301
// passes are timed inside typeck
302302
let (method_map, vtable_map) = typeck::check_crate(ty_cx, trait_map, krate);
303303

304+
time(time_passes, "check static items", (), |_|
305+
middle::check_static::check_crate(ty_cx, krate));
306+
304307
// These next two const passes can probably be merged
305308
time(time_passes, "const marking", (), |_|
306309
middle::const_eval::process_crate(krate, ty_cx));

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub mod middle {
6969
pub mod check_loop;
7070
pub mod check_match;
7171
pub mod check_const;
72+
pub mod check_static;
7273
pub mod lint;
7374
pub mod borrowck;
7475
pub mod dataflow;

src/librustc/middle/check_static.rs

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Verifies that the types and values of static items
12+
// are safe. The rules enforced by this module are:
13+
//
14+
// - For each *mutable* static item, it checks that its **type**:
15+
// - doesn't have a destructor
16+
// - doesn't own an owned pointer
17+
//
18+
// - For each *immutable* static item, it checks that its **value**:
19+
// - doesn't own owned, managed pointers
20+
// - doesn't contain a struct literal or a call to an enum variant / struct constructor where
21+
// - the type of the struct/enum is not freeze
22+
// - the type of the struct/enum has a dtor
23+
24+
use middle::ty;
25+
26+
use syntax::ast;
27+
use syntax::codemap::Span;
28+
use syntax::visit::Visitor;
29+
use syntax::visit;
30+
use syntax::print::pprust;
31+
32+
33+
fn safe_type_for_static_mut(cx: ty::ctxt, e: &ast::Expr) -> Option<~str> {
34+
let node_ty = ty::node_id_to_type(cx, e.id);
35+
let tcontents = ty::type_contents(cx, node_ty);
36+
debug!("safe_type_for_static_mut(dtor={}, managed={}, owned={})",
37+
tcontents.has_dtor(), tcontents.owns_managed(), tcontents.owns_owned())
38+
39+
let suffix = if tcontents.has_dtor() {
40+
"destructors"
41+
} else if tcontents.owns_managed() {
42+
"managed pointers"
43+
} else if tcontents.owns_owned() {
44+
"owned pointers"
45+
} else {
46+
return None;
47+
};
48+
49+
Some(format!("mutable static items are not allowed to have {}", suffix))
50+
}
51+
52+
struct CheckStaticVisitor {
53+
tcx: ty::ctxt,
54+
}
55+
56+
pub fn check_crate(tcx: ty::ctxt, krate: &ast::Crate) {
57+
visit::walk_crate(&mut CheckStaticVisitor { tcx: tcx }, krate, false)
58+
}
59+
60+
impl CheckStaticVisitor {
61+
62+
fn report_error(&self, span: Span, result: Option<~str>) -> bool {
63+
match result {
64+
None => { false }
65+
Some(msg) => {
66+
self.tcx.sess.span_err(span, msg);
67+
true
68+
}
69+
}
70+
}
71+
}
72+
73+
impl Visitor<bool> for CheckStaticVisitor {
74+
75+
fn visit_item(&mut self, i: &ast::Item, _is_const: bool) {
76+
debug!("visit_item(item={})", pprust::item_to_str(i));
77+
match i.node {
78+
ast::ItemStatic(_, mutability, expr) => {
79+
match mutability {
80+
ast::MutImmutable => {
81+
self.visit_expr(expr, true);
82+
}
83+
ast::MutMutable => {
84+
self.report_error(expr.span, safe_type_for_static_mut(self.tcx, expr));
85+
}
86+
}
87+
}
88+
_ => { visit::walk_item(self, i, false) }
89+
}
90+
}
91+
92+
/// This method is used to enforce the constraints on
93+
/// immutable static items. It walks through the *value*
94+
/// of the item walking down the expression and evaluating
95+
/// every nested expression. if the expression is not part
96+
/// of a static item, this method does nothing but walking
97+
/// down through it.
98+
fn visit_expr(&mut self, e: &ast::Expr, is_const: bool) {
99+
debug!("visit_expr(expr={})", pprust::expr_to_str(e));
100+
101+
if !is_const {
102+
return visit::walk_expr(self, e, is_const);
103+
}
104+
105+
match e.node {
106+
ast::ExprField(..) | ast::ExprVec(..) |
107+
ast::ExprBlock(..) | ast::ExprTup(..) |
108+
ast::ExprVstore(_, ast::ExprVstoreSlice) => {
109+
visit::walk_expr(self, e, is_const);
110+
}
111+
ast::ExprUnary(ast::UnBox, _) => {
112+
self.tcx.sess.span_err(e.span,
113+
"static items are not allowed to have managed pointers");
114+
}
115+
ast::ExprBox(..) |
116+
ast::ExprUnary(ast::UnUniq, _) |
117+
ast::ExprVstore(_, ast::ExprVstoreUniq) => {
118+
self.tcx.sess.span_err(e.span,
119+
"static items are not allowed to have owned pointers");
120+
}
121+
_ => {
122+
let node_ty = ty::node_id_to_type(self.tcx, e.id);
123+
match ty::get(node_ty).sty {
124+
ty::ty_struct(did, _) |
125+
ty::ty_enum(did, _) => {
126+
if ty::has_dtor(self.tcx, did) {
127+
self.report_error(e.span,
128+
Some(~"static items are not allowed to have destructors"));
129+
return;
130+
}
131+
}
132+
_ => {}
133+
}
134+
visit::walk_expr(self, e, is_const);
135+
}
136+
}
137+
}
138+
}

src/librustc/middle/ty.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,10 @@ impl TypeContents {
19501950
self.intersects(TC::OwnsManaged)
19511951
}
19521952

1953+
pub fn owns_owned(&self) -> bool {
1954+
self.intersects(TC::OwnsOwned)
1955+
}
1956+
19531957
pub fn is_freezable(&self, _: ctxt) -> bool {
19541958
!self.intersects(TC::Nonfreezable)
19551959
}
@@ -2042,6 +2046,10 @@ impl fmt::Show for TypeContents {
20422046
}
20432047
}
20442048

2049+
pub fn type_has_dtor(cx: ctxt, t: ty::t) -> bool {
2050+
type_contents(cx, t).has_dtor()
2051+
}
2052+
20452053
pub fn type_is_static(cx: ctxt, t: ty::t) -> bool {
20462054
type_contents(cx, t).is_static(cx)
20472055
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
#[feature(managed_boxes)];
11+
12+
// Verifies all possible restrictions for static items values.
13+
14+
struct WithDtor;
15+
16+
impl Drop for WithDtor {
17+
fn drop(&mut self) {}
18+
}
19+
20+
// This enum will be used to test the following rules:
21+
// 1. Variants are safe for static
22+
// 2. Expr calls are allowed as long as they arguments are safe
23+
// 3. Expr calls with unsafe arguments for static items are rejected
24+
enum SafeEnum {
25+
Variant1,
26+
Variant2(int),
27+
Variant3(WithDtor),
28+
Variant4(~str)
29+
}
30+
31+
// These should be ok
32+
static STATIC1: SafeEnum = Variant1;
33+
static STATIC2: SafeEnum = Variant2(0);
34+
35+
// This one should fail
36+
static STATIC3: SafeEnum = Variant3(WithDtor);
37+
//~^ ERROR static items are not allowed to have destructors
38+
39+
40+
// This enum will be used to test that variants
41+
// are considered unsafe if their enum type implements
42+
// a destructor.
43+
enum UnsafeEnum {
44+
Variant5,
45+
Variant6(int)
46+
}
47+
48+
impl Drop for UnsafeEnum {
49+
fn drop(&mut self) {}
50+
}
51+
52+
53+
static STATIC4: UnsafeEnum = Variant5;
54+
//~^ ERROR static items are not allowed to have destructors
55+
static STATIC5: UnsafeEnum = Variant6(0);
56+
//~^ ERROR static items are not allowed to have destructors
57+
58+
59+
struct SafeStruct {
60+
field1: SafeEnum,
61+
field2: SafeEnum,
62+
}
63+
64+
65+
// Struct fields are safe, hence this static should be safe
66+
static STATIC6: SafeStruct = SafeStruct{field1: Variant1, field2: Variant2(0)};
67+
68+
// field2 has an unsafe value, hence this should fail
69+
static STATIC7: SafeStruct = SafeStruct{field1: Variant1, field2: Variant3(WithDtor)};
70+
//~^ ERROR static items are not allowed to have destructors
71+
72+
// Test variadic constructor for structs. The base struct should be examined
73+
// as well as every field persent in the constructor.
74+
// This example shouldn't fail because all the fields are safe.
75+
static STATIC8: SafeStruct = SafeStruct{field1: Variant1,
76+
..SafeStruct{field1: Variant1, field2: Variant1}};
77+
78+
// This example should fail because field1 in the base struct is not safe
79+
static STATIC9: SafeStruct = SafeStruct{field1: Variant1,
80+
..SafeStruct{field1: Variant3(WithDtor), field2: Variant1}};
81+
//~^ ERROR static items are not allowed to have destructors
82+
83+
struct UnsafeStruct;
84+
85+
impl Drop for UnsafeStruct {
86+
fn drop(&mut self) {}
87+
}
88+
89+
// Types with destructors are not allowed for statics
90+
static STATIC10: UnsafeStruct = UnsafeStruct;
91+
//~^ ERROR static items are not allowed to have destructor
92+
93+
static STATIC11: ~str = ~"Owned pointers are not allowed either";
94+
//~^ ERROR static items are not allowed to have owned pointers
95+
96+
// The following examples test that mutable structs are just forbidden
97+
// to have types with destructors
98+
// These should fail
99+
static mut STATIC12: UnsafeStruct = UnsafeStruct;
100+
//~^ ERROR mutable static items are not allowed to have destructors
101+
102+
static mut STATIC13: SafeStruct = SafeStruct{field1: Variant1, field2: Variant3(WithDtor)};
103+
//~^ ERROR mutable static items are not allowed to have destructors
104+
105+
static mut STATIC14: SafeStruct = SafeStruct{field1: Variant1, field2: Variant4(~"str")};
106+
//~^ ERROR mutable static items are not allowed to have destructors
107+
108+
static STATIC15: &'static [~str] = &'static [~"str", ~"str"];
109+
//~^ ERROR static items are not allowed to have owned pointers
110+
//~^^ ERROR static items are not allowed to have owned pointers
111+
112+
static STATIC16: (~str, ~str) = (~"str", ~"str");
113+
//~^ ERROR static items are not allowed to have owned pointers
114+
//~^^ ERROR static items are not allowed to have owned pointers
115+
116+
static mut STATIC17: SafeEnum = Variant1;
117+
//~^ ERROR mutable static items are not allowed to have destructors
118+
119+
static STATIC18: @SafeStruct = @SafeStruct{field1: Variant1, field2: Variant2(0)};
120+
//~^ ERROR static items are not allowed to have managed pointers
121+
122+
static STATIC19: ~int = box 3;
123+
//~^ ERROR static items are not allowed to have owned pointers
124+
125+
pub fn main() {
126+
let y = { static x: ~int = ~3; x };
127+
//~^ ERROR static items are not allowed to have owned pointers
128+
}

src/test/compile-fail/issue-10487.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010

1111
#[feature(managed_boxes)];
1212

13-
static x: ~[int] = ~[123, 456]; //~ ERROR: cannot allocate vectors in constant expressions
13+
static x: ~[int] = ~[123, 456]; //~ ERROR: static items are not allowed to have owned pointers
1414

1515
fn main() {}

0 commit comments

Comments
 (0)