]> git.lizzy.rs Git - rust.git/blob - src/libstd/panicking.rs
libstd: add example for PathBuf::push
[rust.git] / src / libstd / panicking.rs
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 use prelude::v1::*;
12 use io::prelude::*;
13
14 use any::Any;
15 use cell::Cell;
16 use cell::RefCell;
17 use intrinsics;
18 use sys::stdio::Stderr;
19 use sys_common::backtrace;
20 use sys_common::thread_info;
21 use sys_common::util;
22
23 thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
24
25 thread_local! {
26     pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
27         RefCell::new(None)
28     }
29 }
30
31 fn log_panic(obj: &(Any+Send), file: &'static str, line: u32,
32              log_backtrace: bool) {
33     let msg = match obj.downcast_ref::<&'static str>() {
34         Some(s) => *s,
35         None => match obj.downcast_ref::<String>() {
36             Some(s) => &s[..],
37             None => "Box<Any>",
38         }
39     };
40     let mut err = Stderr::new().ok();
41     let thread = thread_info::current_thread();
42     let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
43
44     let write = |err: &mut ::io::Write| {
45         let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}",
46                          name, msg, file, line);
47         if log_backtrace {
48             let _ = backtrace::write(err);
49         }
50     };
51
52     let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
53     match (prev, err.as_mut()) {
54         (Some(mut stderr), _) => {
55             write(&mut *stderr);
56             let mut s = Some(stderr);
57             LOCAL_STDERR.with(|slot| {
58                 *slot.borrow_mut() = s.take();
59             });
60         }
61         (None, Some(ref mut err)) => { write(err) }
62         _ => {}
63     }
64 }
65
66 pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
67     let panics = PANIC_COUNT.with(|s| {
68         let count = s.get() + 1;
69         s.set(count);
70         count
71     });
72
73     // If this is the third nested call, on_panic triggered the last panic,
74     // otherwise the double-panic check would have aborted the process.
75     // Even if it is likely that on_panic was unable to log the backtrace,
76     // abort immediately to avoid infinite recursion, so that attaching a
77     // debugger provides a useable stacktrace.
78     if panics >= 3 {
79         util::dumb_print(format_args!("thread panicked while processing \
80                                        panic. aborting."));
81         unsafe { intrinsics::abort() }
82     }
83
84     // If this is a double panic, make sure that we print a backtrace
85     // for this panic. Otherwise only print it if logging is enabled.
86     let log_backtrace = panics >= 2 || backtrace::log_enabled();
87     log_panic(obj, file, line, log_backtrace);
88
89     if panics >= 2 {
90         // If a thread panics while it's already unwinding then we
91         // have limited options. Currently our preference is to
92         // just abort. In the future we may consider resuming
93         // unwinding or otherwise exiting the thread cleanly.
94         util::dumb_print(format_args!("thread panicked while panicking. \
95                                        aborting."));
96         unsafe { intrinsics::abort() }
97     }
98 }