|
5 | 5 | use crate::any::Any;
|
6 | 6 | use crate::collections;
|
7 | 7 | use crate::panicking;
|
| 8 | +use crate::sync::atomic::{AtomicUsize, Ordering}; |
8 | 9 | use crate::sync::{Mutex, RwLock};
|
9 | 10 | use crate::thread::Result;
|
10 | 11 |
|
@@ -202,5 +203,118 @@ pub fn always_abort() {
|
202 | 203 | crate::panicking::panic_count::set_always_abort();
|
203 | 204 | }
|
204 | 205 |
|
| 206 | +/// The configuration for whether and how the default panic hook will capture |
| 207 | +/// and display the backtrace. |
| 208 | +#[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 209 | +#[unstable(feature = "panic_backtrace_config", issue = "93346")] |
| 210 | +#[non_exhaustive] |
| 211 | +pub enum BacktraceStyle { |
| 212 | + /// Prints a terser backtrace which ideally only contains relevant |
| 213 | + /// information. |
| 214 | + Short, |
| 215 | + /// Prints a backtrace with all possible information. |
| 216 | + Full, |
| 217 | + /// Disable collecting and displaying backtraces. |
| 218 | + Off, |
| 219 | +} |
| 220 | + |
| 221 | +impl BacktraceStyle { |
| 222 | + pub(crate) fn full() -> Option<Self> { |
| 223 | + if cfg!(feature = "backtrace") { Some(BacktraceStyle::Full) } else { None } |
| 224 | + } |
| 225 | + |
| 226 | + fn as_usize(self) -> usize { |
| 227 | + match self { |
| 228 | + BacktraceStyle::Short => 1, |
| 229 | + BacktraceStyle::Full => 2, |
| 230 | + BacktraceStyle::Off => 3, |
| 231 | + } |
| 232 | + } |
| 233 | + |
| 234 | + fn from_usize(s: usize) -> Option<Self> { |
| 235 | + Some(match s { |
| 236 | + 0 => return None, |
| 237 | + 1 => BacktraceStyle::Short, |
| 238 | + 2 => BacktraceStyle::Full, |
| 239 | + 3 => BacktraceStyle::Off, |
| 240 | + _ => unreachable!(), |
| 241 | + }) |
| 242 | + } |
| 243 | +} |
| 244 | + |
| 245 | +// Tracks whether we should/can capture a backtrace, and how we should display |
| 246 | +// that backtrace. |
| 247 | +// |
| 248 | +// Internally stores equivalent of an Option<BacktraceStyle>. |
| 249 | +static SHOULD_CAPTURE: AtomicUsize = AtomicUsize::new(0); |
| 250 | + |
| 251 | +/// Configure whether the default panic hook will capture and display a |
| 252 | +/// backtrace. |
| 253 | +/// |
| 254 | +/// The default value for this setting may be set by the `RUST_BACKTRACE` |
| 255 | +/// environment variable; see the details in [`get_backtrace_style`]. |
| 256 | +#[unstable(feature = "panic_backtrace_config", issue = "93346")] |
| 257 | +pub fn set_backtrace_style(style: BacktraceStyle) { |
| 258 | + if !cfg!(feature = "backtrace") { |
| 259 | + // If the `backtrace` feature of this crate isn't enabled, skip setting. |
| 260 | + return; |
| 261 | + } |
| 262 | + SHOULD_CAPTURE.store(style.as_usize(), Ordering::Release); |
| 263 | +} |
| 264 | + |
| 265 | +/// Checks whether the standard library's panic hook will capture and print a |
| 266 | +/// backtrace. |
| 267 | +/// |
| 268 | +/// This function will, if a backtrace style has not been set via |
| 269 | +/// [`set_backtrace_style`], read the environment variable `RUST_BACKTRACE` to |
| 270 | +/// determine a default value for the backtrace formatting: |
| 271 | +/// |
| 272 | +/// The first call to `get_backtrace_style` may read the `RUST_BACKTRACE` |
| 273 | +/// environment variable if `set_backtrace_style` has not been called to |
| 274 | +/// override the default value. After a call to `set_backtrace_style` or |
| 275 | +/// `get_backtrace_style`, any changes to `RUST_BACKTRACE` will have no effect. |
| 276 | +/// |
| 277 | +/// `RUST_BACKTRACE` is read according to these rules: |
| 278 | +/// |
| 279 | +/// * `0` for `BacktraceStyle::Off` |
| 280 | +/// * `full` for `BacktraceStyle::Full` |
| 281 | +/// * `1` for `BacktraceStyle::Short` |
| 282 | +/// * Other values are currently `BacktraceStyle::Short`, but this may change in |
| 283 | +/// the future |
| 284 | +/// |
| 285 | +/// Returns `None` if backtraces aren't currently supported. |
| 286 | +#[unstable(feature = "panic_backtrace_config", issue = "93346")] |
| 287 | +pub fn get_backtrace_style() -> Option<BacktraceStyle> { |
| 288 | + if !cfg!(feature = "backtrace") { |
| 289 | + // If the `backtrace` feature of this crate isn't enabled quickly return |
| 290 | + // `Unsupported` so this can be constant propagated all over the place |
| 291 | + // to optimize away callers. |
| 292 | + return None; |
| 293 | + } |
| 294 | + if let Some(style) = BacktraceStyle::from_usize(SHOULD_CAPTURE.load(Ordering::Acquire)) { |
| 295 | + return Some(style); |
| 296 | + } |
| 297 | + |
| 298 | + // Setting environment variables for Fuchsia components isn't a standard |
| 299 | + // or easily supported workflow. For now, display backtraces by default. |
| 300 | + let format = if cfg!(target_os = "fuchsia") { |
| 301 | + BacktraceStyle::Full |
| 302 | + } else { |
| 303 | + crate::env::var_os("RUST_BACKTRACE") |
| 304 | + .map(|x| { |
| 305 | + if &x == "0" { |
| 306 | + BacktraceStyle::Off |
| 307 | + } else if &x == "full" { |
| 308 | + BacktraceStyle::Full |
| 309 | + } else { |
| 310 | + BacktraceStyle::Short |
| 311 | + } |
| 312 | + }) |
| 313 | + .unwrap_or(BacktraceStyle::Off) |
| 314 | + }; |
| 315 | + set_backtrace_style(format); |
| 316 | + Some(format) |
| 317 | +} |
| 318 | + |
205 | 319 | #[cfg(test)]
|
206 | 320 | mod tests;
|
0 commit comments