Skip to content

Commit 4f83227

Browse files
committed
[debug] Add debug::Error, a wrapper for attaching context to errors
This type cannot be created except via special macros in the `debug` module that generate log statements. We may eventually also attach extra debugging information to errors, and this type is a good place to do so. Signed-off-by: Miguel Young de la Sota <[email protected]>
1 parent 81ddced commit 4f83227

File tree

8 files changed

+135
-13
lines changed

8 files changed

+135
-13
lines changed

src/cert/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ impl From<untrusted::EndOfInput> for Error {
9595
}
9696
}
9797

98+
debug_from!(Error => io::Error, untrusted::EndOfInput);
99+
98100
impl<'cert> Cert<'cert> {
99101
/// Parses `cert`, producing a parsed certificate in the given format.
100102
///

src/debug.rs

Lines changed: 105 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,137 @@
1111
//! Manticore code *should not* call into the [`log`] crate directly outside of
1212
//! this module.
1313
14+
// TODO: Remove this once we start using these macros in Manticore.
1415
#![allow(unused)]
1516

17+
use core::fmt;
18+
1619
#[cfg(doc)]
1720
use __raw_log as log;
1821

22+
/// A wrapped Manticore error.
23+
///
24+
/// This type should always be referred to as `manticore::Error`. It represents
25+
/// an error with extra (potentially redacted) information attached. This type
26+
/// cannot be directly created by users of the library.
27+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
28+
pub struct Error<E> {
29+
inner: E,
30+
}
31+
32+
impl<E> Error<E> {
33+
/// Creates a new `Error`. This function is an implementation detail,
34+
/// and should not be called by users.
35+
#[doc(hidden)]
36+
pub fn __new(inner: E) -> Self {
37+
Self { inner }
38+
}
39+
40+
/// Transforms the wrapper error by way of an [`Into`] conversion.
41+
///
42+
/// Generally, this function should not be necessary, because Manticore-
43+
/// defined error types manually implement the relevant [`From`]
44+
/// implementations for `manticore::Error`, which in turn call `cast()`.
45+
pub fn cast<F>(self) -> Error<F>
46+
where
47+
F: From<E>,
48+
{
49+
Error {
50+
inner: self.inner.into(),
51+
}
52+
}
53+
54+
/// Gets the wrapper error.
55+
pub fn into_inner(self) -> E {
56+
self.inner
57+
}
58+
}
59+
60+
impl<E> AsRef<E> for Error<E> {
61+
fn as_ref(&self) -> &E {
62+
&self.inner
63+
}
64+
}
65+
66+
impl<E> AsMut<E> for Error<E> {
67+
fn as_mut(&mut self) -> &mut E {
68+
&mut self.inner
69+
}
70+
}
71+
72+
impl<E: fmt::Display> fmt::Display for Error<E> {
73+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74+
struct DisplayAsDebug<'a, E>(&'a E);
75+
impl<E: fmt::Display> fmt::Debug for DisplayAsDebug<'_, E> {
76+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77+
self.0.fmt(f)
78+
}
79+
}
80+
81+
f.debug_struct("manticore::Error")
82+
.field("inner", &DisplayAsDebug(&self.inner))
83+
.finish()
84+
}
85+
}
86+
87+
/// Generates `From` implementations for `manticore::Error`.
88+
///
89+
/// We would like to write this `impl`:
90+
/// ```compile_fail
91+
/// # use manticore::Error;
92+
/// impl<E1, E2> From<Error<E1>> for Error<E2> where E2: From<E1> {
93+
/// fn from(e: Error<E1>) -> Error<E2> {
94+
/// e.cast()
95+
/// }
96+
/// }
97+
/// ```
98+
///
99+
/// Unfortunately, the trait coherence rules mean that for `E1 == E2`,
100+
/// this conflicts with the standard library's `impl<T> From<T> for T`
101+
/// impl. We work around this by calling this macro for every Manticore
102+
/// error definition that has `From` impls.
103+
macro_rules! debug_from {
104+
($e:ty => $($f:ty),+ $(,)?) => {$(
105+
impl From<$crate::Error<$f>> for $crate::Error<$e> {
106+
fn from(e: $crate::Error<$f>) -> Self {
107+
e.cast()
108+
}
109+
}
110+
)*}
111+
}
112+
19113
/// Checks a condition, logging if it fails.
20114
///
21115
/// If the condition does not hold, constructs the given error, logs it, and
22116
/// returns out of the current function with it.
23117
macro_rules! check {
24118
($cond:expr, $error:expr) => {
25119
if !$cond {
26-
let e = $error;
27-
error!(
120+
let error = $error;
121+
trace!(
122+
error,
28123
"check failure: `{}`; returned {:?}"
29-
stringify!($cond), e
30-
);
31-
return Err(e);
124+
stringify!($cond), error,
125+
)?;
32126
}
33127
}
34128
}
35129

36130
/// Logs a newly-created error value and returns it.
37131
///
38-
/// This function is useful for marking where errors originate in tests.
132+
/// This macro is the main way to generate [`Error`] values.
133+
///
39134
/// For example, instead of writing `foo.ok_or(MyError)`, instead write
40135
/// `foo.ok_or_else(|| trace!(MyError))`.
41136
macro_rules! trace {
42137
($error:expr, $($format:tt)+) => {{
43138
error!($($format)+);
44-
$error
139+
$crate::debug::Error::__new($error)
45140
}};
46141
($error:expr) => {{
47-
let e = $error;
48-
error!("generated error: `{:?}`", e);
49-
e
142+
let error = $error;
143+
error!("generated error: `{:?}`", error);
144+
$crate::debug::Error::__new(error)
50145
}};
51146
}
52147

src/hardware/flash.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl From<OutOfMemory> for Error {
5656
Error::Internal
5757
}
5858
}
59+
debug_from!(Error => OutOfMemory);
5960

6061
/// Provides access to a flash-like storage device.
6162
///

src/lib.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@
5656
// `debug`.
5757
#[cfg(feature = "log")]
5858
extern crate log as __raw_log;
59+
#[macro_use]
60+
mod debug;
5961

6062
#[macro_use]
6163
pub mod protocol;
62-
#[macro_use]
63-
mod debug;
6464

6565
#[cfg(feature = "serde")]
6666
mod serde;
@@ -73,3 +73,12 @@ pub mod manifest;
7373
pub mod mem;
7474
pub mod net;
7575
pub mod server;
76+
77+
pub use debug::Error;
78+
79+
/// [`Result`] type to use throughout Manticore, which incorporates the
80+
/// [`manticore::Error`] type.
81+
///
82+
/// [`Result`]: std::result::Result
83+
/// [`manticore::Error`]: crate::Error
84+
pub type Result<T, E> = core::result::Result<T, Error<E>>;

src/manifest/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ impl From<sha256::Error> for Error {
218218
}
219219
}
220220

221+
debug_from!(Error => io::Error, flash::Error, OutOfMemory, sig::Error, sha256::Error);
222+
221223
/// A manifest type.
222224
///
223225
/// A type that implements this trait is not itself a "parsed" instance of the

src/net.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ impl From<io::Error> for Error {
5050
}
5151
}
5252

53+
debug_from!(Error => io::Error);
54+
5355
/// Represents a physical port that can be used to interact with host devices.
5456
///
5557
/// This trait provides a generic mechanism for recieving and responding to

src/protocol/wire.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ impl From<OutOfMemory> for FromWireError {
5757
}
5858
}
5959

60+
debug_from!(FromWireError => io::Error, OutOfMemory);
61+
6062
/// A type which can be serialized into the Cerberus wire format.
6163
pub trait ToWire: Sized {
6264
/// Serializes `self` into `w`.
@@ -76,6 +78,8 @@ impl From<io::Error> for ToWireError {
7678
}
7779
}
7880

81+
debug_from!(ToWireError => io::Error);
82+
7983
/// Represents a C-like enum that can be converted to and from a wire
8084
/// representation as well as to and from a string representation.
8185
///
@@ -231,7 +235,12 @@ macro_rules! wire_enum {
231235
impl core::str::FromStr for $name {
232236
type Err = $crate::protocol::wire::WireEnumFromStrError;
233237

234-
fn from_str(s: &str) -> Result<Self, $crate::protocol::wire::WireEnumFromStrError> {
238+
fn from_str(
239+
s: &str
240+
) -> core::result::Result<
241+
Self,
242+
$crate::protocol::wire::WireEnumFromStrError
243+
> {
235244
use $crate::protocol::wire::WireEnum;
236245

237246
match $name::from_name(s) {

src/server/handler.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ impl From<net::Error> for Error {
128128
}
129129
}
130130

131+
debug_from!(Error => FromWireError, ToWireError, net::Error);
132+
131133
/// A request handler builder.
132134
///
133135
/// See the module documentation for more information.

0 commit comments

Comments
 (0)