]>
Commit | Line | Data |
---|---|---|
3157f602 XL |
1 | // Copyright 2016 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 | ||
9e0c209e | 11 | #![feature(untagged_unions)] |
3157f602 XL |
12 | |
13 | use std::cell::{Cell, RefCell}; | |
14 | use std::panic; | |
15 | use std::usize; | |
16 | ||
17 | struct InjectedFailure; | |
18 | ||
19 | struct Allocator { | |
20 | data: RefCell<Vec<bool>>, | |
21 | failing_op: usize, | |
22 | cur_ops: Cell<usize>, | |
23 | } | |
24 | ||
25 | impl panic::UnwindSafe for Allocator {} | |
26 | impl panic::RefUnwindSafe for Allocator {} | |
27 | ||
28 | impl Drop for Allocator { | |
29 | fn drop(&mut self) { | |
30 | let data = self.data.borrow(); | |
31 | if data.iter().any(|d| *d) { | |
32 | panic!("missing free: {:?}", data); | |
33 | } | |
34 | } | |
35 | } | |
36 | ||
37 | impl Allocator { | |
38 | fn new(failing_op: usize) -> Self { | |
39 | Allocator { | |
40 | failing_op: failing_op, | |
41 | cur_ops: Cell::new(0), | |
42 | data: RefCell::new(vec![]) | |
43 | } | |
44 | } | |
45 | fn alloc(&self) -> Ptr { | |
46 | self.cur_ops.set(self.cur_ops.get() + 1); | |
47 | ||
48 | if self.cur_ops.get() == self.failing_op { | |
49 | panic!(InjectedFailure); | |
50 | } | |
51 | ||
52 | let mut data = self.data.borrow_mut(); | |
53 | let addr = data.len(); | |
54 | data.push(true); | |
55 | Ptr(addr, self) | |
56 | } | |
57 | } | |
58 | ||
59 | struct Ptr<'a>(usize, &'a Allocator); | |
60 | impl<'a> Drop for Ptr<'a> { | |
61 | fn drop(&mut self) { | |
62 | match self.1.data.borrow_mut()[self.0] { | |
63 | false => { | |
64 | panic!("double free at index {:?}", self.0) | |
65 | } | |
66 | ref mut d => *d = false | |
67 | } | |
68 | ||
69 | self.1.cur_ops.set(self.1.cur_ops.get()+1); | |
70 | ||
71 | if self.1.cur_ops.get() == self.1.failing_op { | |
72 | panic!(InjectedFailure); | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
3157f602 XL |
77 | fn dynamic_init(a: &Allocator, c: bool) { |
78 | let _x; | |
79 | if c { | |
80 | _x = Some(a.alloc()); | |
81 | } | |
82 | } | |
83 | ||
3157f602 XL |
84 | fn dynamic_drop(a: &Allocator, c: bool) { |
85 | let x = a.alloc(); | |
86 | if c { | |
87 | Some(x) | |
88 | } else { | |
89 | None | |
90 | }; | |
91 | } | |
92 | ||
7cac9316 XL |
93 | struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>); |
94 | fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) { | |
95 | for i in 0..2 { | |
96 | let x; | |
97 | let y; | |
98 | if (c0 && i == 0) || (c1 && i == 1) { | |
99 | x = (a.alloc(), a.alloc(), a.alloc()); | |
100 | y = TwoPtrs(a.alloc(), a.alloc()); | |
101 | if c { | |
102 | drop(x.1); | |
103 | drop(y.0); | |
104 | } | |
105 | } | |
106 | } | |
107 | } | |
108 | ||
041b39d2 XL |
109 | fn field_assignment(a: &Allocator, c0: bool) { |
110 | let mut x = (TwoPtrs(a.alloc(), a.alloc()), a.alloc()); | |
111 | ||
112 | x.1 = a.alloc(); | |
113 | x.1 = a.alloc(); | |
114 | ||
115 | let f = (x.0).0; | |
116 | if c0 { | |
117 | (x.0).0 = f; | |
118 | } | |
119 | } | |
120 | ||
3157f602 XL |
121 | fn assignment2(a: &Allocator, c0: bool, c1: bool) { |
122 | let mut _v = a.alloc(); | |
123 | let mut _w = a.alloc(); | |
124 | if c0 { | |
125 | drop(_v); | |
126 | } | |
127 | _v = _w; | |
128 | if c1 { | |
129 | _w = a.alloc(); | |
130 | } | |
131 | } | |
132 | ||
3157f602 XL |
133 | fn assignment1(a: &Allocator, c0: bool) { |
134 | let mut _v = a.alloc(); | |
135 | let mut _w = a.alloc(); | |
136 | if c0 { | |
137 | drop(_v); | |
138 | } | |
139 | _v = _w; | |
140 | } | |
141 | ||
9e0c209e SL |
142 | #[allow(unions_with_drop_fields)] |
143 | union Boxy<T> { | |
144 | a: T, | |
145 | b: T, | |
146 | } | |
147 | ||
148 | fn union1(a: &Allocator) { | |
149 | unsafe { | |
150 | let mut u = Boxy { a: a.alloc() }; | |
151 | u.b = a.alloc(); | |
152 | drop(u.a); | |
153 | } | |
154 | } | |
155 | ||
7cac9316 XL |
156 | fn array_simple(a: &Allocator) { |
157 | let _x = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; | |
158 | } | |
159 | ||
160 | fn vec_simple(a: &Allocator) { | |
161 | let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()]; | |
162 | } | |
163 | ||
3157f602 XL |
164 | fn run_test<F>(mut f: F) |
165 | where F: FnMut(&Allocator) | |
166 | { | |
167 | let first_alloc = Allocator::new(usize::MAX); | |
168 | f(&first_alloc); | |
169 | ||
170 | for failing_op in 1..first_alloc.cur_ops.get()+1 { | |
171 | let alloc = Allocator::new(failing_op); | |
172 | let alloc = &alloc; | |
173 | let f = panic::AssertUnwindSafe(&mut f); | |
174 | let result = panic::catch_unwind(move || { | |
175 | f.0(alloc); | |
176 | }); | |
177 | match result { | |
178 | Ok(..) => panic!("test executed {} ops but now {}", | |
179 | first_alloc.cur_ops.get(), alloc.cur_ops.get()), | |
180 | Err(e) => { | |
181 | if e.downcast_ref::<InjectedFailure>().is_none() { | |
182 | panic::resume_unwind(e); | |
183 | } | |
184 | } | |
185 | } | |
186 | } | |
187 | } | |
188 | ||
9e0c209e SL |
189 | fn run_test_nopanic<F>(mut f: F) |
190 | where F: FnMut(&Allocator) | |
191 | { | |
192 | let first_alloc = Allocator::new(usize::MAX); | |
193 | f(&first_alloc); | |
194 | } | |
195 | ||
3157f602 XL |
196 | fn main() { |
197 | run_test(|a| dynamic_init(a, false)); | |
198 | run_test(|a| dynamic_init(a, true)); | |
199 | run_test(|a| dynamic_drop(a, false)); | |
200 | run_test(|a| dynamic_drop(a, true)); | |
201 | ||
202 | run_test(|a| assignment2(a, false, false)); | |
203 | run_test(|a| assignment2(a, false, true)); | |
204 | run_test(|a| assignment2(a, true, false)); | |
205 | run_test(|a| assignment2(a, true, true)); | |
206 | ||
207 | run_test(|a| assignment1(a, false)); | |
208 | run_test(|a| assignment1(a, true)); | |
9e0c209e | 209 | |
7cac9316 XL |
210 | run_test(|a| array_simple(a)); |
211 | run_test(|a| vec_simple(a)); | |
212 | ||
213 | run_test(|a| struct_dynamic_drop(a, false, false, false)); | |
214 | run_test(|a| struct_dynamic_drop(a, false, false, true)); | |
215 | run_test(|a| struct_dynamic_drop(a, false, true, false)); | |
216 | run_test(|a| struct_dynamic_drop(a, false, true, true)); | |
217 | run_test(|a| struct_dynamic_drop(a, true, false, false)); | |
218 | run_test(|a| struct_dynamic_drop(a, true, false, true)); | |
219 | run_test(|a| struct_dynamic_drop(a, true, true, false)); | |
220 | run_test(|a| struct_dynamic_drop(a, true, true, true)); | |
221 | ||
041b39d2 XL |
222 | run_test(|a| field_assignment(a, false)); |
223 | run_test(|a| field_assignment(a, true)); | |
224 | ||
9e0c209e | 225 | run_test_nopanic(|a| union1(a)); |
3157f602 | 226 | } |