Skip to content
This repository was archived by the owner on Aug 16, 2021. It is now read-only.

Commit 8854a15

Browse files
authored
Merge pull request #27 from birkenfeld/issue-7
Only generate backtraces with RUST_BACKTRACE set (closes #7)
2 parents 64fb018 + df58ffe commit 8854a15

File tree

3 files changed

+59
-20
lines changed

3 files changed

+59
-20
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ provides a few unique features:
1010
"chain" errors with the `chain_err` method.
1111
* Introducing new errors is trivial. Simple errors can be introduced
1212
at the error site with just a string.
13-
* Errors create and propagate backtraces.
13+
* Errors can create and propagate backtraces.
1414

1515
[Documentation](http://brson.github.io/error-chain/index.html).
1616

src/lib.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//! consistent way - `From` conversion behavior is never specified
1313
//! explicitly.
1414
//! * Errors implement Send.
15-
//! * Errors carry backtraces.
15+
//! * Errors can carry backtraces.
1616
//!
1717
//! Similar to other libraries like [error-type] and [quick-error], this
1818
//! library defines a macro, `error_chain!` that declares the types
@@ -40,9 +40,9 @@
4040
//! errors.
4141
//! * It provides automatic `From` conversions between any other error
4242
//! type that hides the type of the other error in the `cause` box.
43-
//! * It collects a single backtrace at the earliest opportunity and
44-
//! propagates it down the stack through `From` and `ChainErr`
45-
//! conversions.
43+
//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at
44+
//! the earliest opportunity and propagates it down the stack through
45+
//! `From` and `ChainErr` conversions.
4646
//!
4747
//! To accomplish its goals it makes some tradeoffs:
4848
//!
@@ -175,13 +175,13 @@
175175
//! #[derive(Debug)]
176176
//! pub struct Error(pub ErrorKind,
177177
//! pub Option<Box<StdError + Send>>,
178-
//! pub Arc<error_chain::Backtrace>);
178+
//! pub Option<Arc<error_chain::Backtrace>>);
179179
//!
180180
//! impl Error {
181181
//! pub fn kind(&self) -> &ErrorKind { ... }
182182
//! pub fn into_kind(self) -> ErrorKind { ... }
183183
//! pub fn iter(&self) -> error_chain::ErrorChainIter { ... }
184-
//! pub fn backtrace(&self) -> &error_chain::Backtrace { ... }
184+
//! pub fn backtrace(&self) -> Option<&error_chain::Backtrace> { ... }
185185
//! }
186186
//!
187187
//! impl StdError for Error { ... }
@@ -293,10 +293,11 @@
293293
//!
294294
//! ## Backtraces
295295
//!
296-
//! The earliest non-foreign error to be generated creates a single
297-
//! backtrace, which is passed through all `From` conversions and
298-
//! `chain_err` invocations of compatible types. To read the backtrace
299-
//! just call the `backtrace()` method.
296+
//! If the `RUST_BACKTRACE` environment variable is set to anything
297+
//! but ``0``, the earliest non-foreign error to be generated creates
298+
//! a single backtrace, which is passed through all `From` conversions
299+
//! and `chain_err` invocations of compatible types. To read the
300+
//! backtrace just call the `backtrace()` method.
300301
//!
301302
//! ## Iteration
302303
//!
@@ -343,7 +344,7 @@ macro_rules! error_chain {
343344
#[derive(Debug)]
344345
pub struct $error_name(pub $error_kind_name,
345346
pub (Option<Box<::std::error::Error + Send>>,
346-
::std::sync::Arc<$crate::Backtrace>));
347+
Option<::std::sync::Arc<$crate::Backtrace>>));
347348

348349
#[allow(unused)]
349350
impl $error_name {
@@ -359,8 +360,8 @@ macro_rules! error_chain {
359360
$crate::ErrorChainIter(Some(self))
360361
}
361362

362-
pub fn backtrace(&self) -> &$crate::Backtrace {
363-
&(self.1).1
363+
pub fn backtrace(&self) -> Option<&$crate::Backtrace> {
364+
(self.1).1.as_ref().map(|v| &**v)
364365
}
365366
}
366367

@@ -402,29 +403,29 @@ macro_rules! error_chain {
402403
fn from(e: $foreign_link_error_path) -> Self {
403404
$error_name(
404405
$error_kind_name::$foreign_link_variant(e),
405-
(None, ::std::sync::Arc::new($crate::Backtrace::new())))
406+
(None, $crate::make_backtrace()))
406407
}
407408
}
408409
) *
409410

410411
impl From<$error_kind_name> for $error_name {
411412
fn from(e: $error_kind_name) -> Self {
412413
$error_name(e,
413-
(None, ::std::sync::Arc::new($crate::Backtrace::new())))
414+
(None, $crate::make_backtrace()))
414415
}
415416
}
416417

417418
impl<'a> From<&'a str> for $error_name {
418419
fn from(s: &'a str) -> Self {
419420
$error_name(s.into(),
420-
(None, ::std::sync::Arc::new($crate::Backtrace::new())))
421+
(None, $crate::make_backtrace()))
421422
}
422423
}
423424

424425
impl From<String> for $error_name {
425426
fn from(s: String) -> Self {
426427
$error_name(s.into(),
427-
(None, ::std::sync::Arc::new($crate::Backtrace::new())))
428+
(None, $crate::make_backtrace()))
428429
}
429430
}
430431

@@ -500,7 +501,7 @@ macro_rules! error_chain {
500501
let e = Box::new(e) as Box<::std::error::Error + Send + 'static>;
501502
let (e, backtrace) = backtrace_from_box(e);
502503
let backtrace = backtrace.unwrap_or_else(
503-
|| ::std::sync::Arc::new($crate::Backtrace::new()));
504+
|| $crate::make_backtrace());
504505

505506
$error_name(callback().into(), (Some(e), backtrace))
506507
})
@@ -513,7 +514,7 @@ macro_rules! error_chain {
513514
// machinery to make it work.
514515
fn backtrace_from_box(mut e: Box<::std::error::Error + Send + 'static>)
515516
-> (Box<::std::error::Error + Send + 'static>,
516-
Option<::std::sync::Arc<$crate::Backtrace>>) {
517+
Option<Option<::std::sync::Arc<$crate::Backtrace>>>) {
517518
let mut backtrace = None;
518519

519520
e = match e.downcast::<$error_name>() {
@@ -657,6 +658,7 @@ macro_rules! error_chain {
657658

658659
use std::error::Error as StdError;
659660
use std::iter::Iterator;
661+
use std::sync::Arc;
660662

661663
pub struct ErrorChainIter<'a>(pub Option<&'a StdError>);
662664

@@ -673,3 +675,13 @@ impl<'a> Iterator for ErrorChainIter<'a> {
673675
}
674676
}
675677
}
678+
679+
/// Returns a backtrace of the current call stack if `RUST_BACKTRACE`
680+
/// is set to anything but ``0``, and `None` otherwise. This is used
681+
/// in the generated error implementations.
682+
pub fn make_backtrace() -> Option<Arc<Backtrace>> {
683+
match std::env::var_os("RUST_BACKTRACE") {
684+
Some(ref val) if val != "0" => Some(Arc::new(Backtrace::new())),
685+
_ => None
686+
}
687+
}

tests/tests.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,33 @@ fn empty() {
129129
error_chain! { };
130130
}
131131

132+
#[test]
133+
fn has_backtrace_depending_on_env() {
134+
use std::env;
135+
136+
error_chain! {
137+
types {}
138+
links {}
139+
foreign_links {}
140+
errors {
141+
MyError
142+
}
143+
}
144+
145+
// missing RUST_BACKTRACE and RUST_BACKTRACE=0
146+
env::remove_var("RUST_BACKTRACE");
147+
let err = Error::from(ErrorKind::MyError);
148+
assert!(err.backtrace().is_none());
149+
env::set_var("RUST_BACKTRACE", "0");
150+
let err = Error::from(ErrorKind::MyError);
151+
assert!(err.backtrace().is_none());
152+
153+
// RUST_BACKTRACE set to anything but 0
154+
env::set_var("RUST_BACKTRACE", "yes");
155+
let err = Error::from(ErrorKind::MyError);
156+
assert!(err.backtrace().is_some());
157+
}
158+
132159
#[cfg(test)]
133160
mod foreign_link_test {
134161

0 commit comments

Comments
 (0)