Skip to content

Commit 6f45848

Browse files
mcykesyog
authored andcommitted
[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]> Fix some syntax and rebase errors Signed-off-by: Kesavan Yogeswaran <[email protected]>
1 parent b11a21b commit 6f45848

File tree

9 files changed

+238
-19
lines changed

9 files changed

+238
-19
lines changed

src/cert/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ impl From<untrusted::EndOfInput> for Error {
104104
}
105105
}
106106

107+
debug_from!(Error => io::Error, untrusted::EndOfInput);
108+
107109
impl<'cert> Cert<'cert> {
108110
/// Parses `cert`, producing a parsed certificate in the given format.
109111
///

src/debug.rs

Lines changed: 133 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,162 @@
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: From<E>>(self) -> Error<F> {
46+
Error {
47+
inner: self.inner.into(),
48+
}
49+
}
50+
51+
/// Gets the wrapped error.
52+
pub fn into_inner(self) -> E {
53+
self.inner
54+
}
55+
}
56+
57+
impl<E> AsRef<E> for Error<E> {
58+
fn as_ref(&self) -> &E {
59+
&self.inner
60+
}
61+
}
62+
63+
impl<E> AsMut<E> for Error<E> {
64+
fn as_mut(&mut self) -> &mut E {
65+
&mut self.inner
66+
}
67+
}
68+
69+
impl<E: fmt::Display> fmt::Display for Error<E> {
70+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71+
struct DisplayAsDebug<'a, E>(&'a E);
72+
impl<E: fmt::Display> fmt::Debug for DisplayAsDebug<'_, E> {
73+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74+
self.0.fmt(f)
75+
}
76+
}
77+
78+
f.debug_struct("manticore::Error")
79+
.field("inner", &DisplayAsDebug(&self.inner))
80+
.finish()
81+
}
82+
}
83+
84+
/// Generates `From` implementations for `manticore::Error`.
85+
///
86+
/// We would like to write this `impl`:
87+
/// ```compile_fail
88+
/// # use manticore::Error;
89+
/// impl<E1, E2> From<Error<E1>> for Error<E2> where E2: From<E1> {
90+
/// fn from(e: Error<E1>) -> Error<E2> {
91+
/// e.cast()
92+
/// }
93+
/// }
94+
/// ```
95+
///
96+
/// Unfortunately, the trait coherence rules mean that for `E1 == E2`,
97+
/// this conflicts with the standard library's `impl<T> From<T> for T`
98+
/// impl. We work around this by calling this macro for every Manticore
99+
/// error definition that has `From` impls.
100+
macro_rules! debug_from {
101+
// An error generic over one type with a single trait bound
102+
($e:ident<$trait:ident: $bound:path> => $($f:ty),+ $(,)?) => {$(
103+
impl<$trait: $bound> From<$crate::Error<$f>> for $crate::Error<$e<$trait>> {
104+
fn from(e: $crate::Error<$f>) -> Self {
105+
e.cast()
106+
}
107+
}
108+
)*};
109+
// An error generic over one type
110+
($e:ident<$trait:ident> => $($f:ty),+ $(,)?) => {$(
111+
impl<$trait> From<$crate::Error<$f>> for $crate::Error<$e<$trait>> {
112+
fn from(e: $crate::Error<$f>) -> Self {
113+
e.cast()
114+
}
115+
}
116+
)*};
117+
($e:ty => $($f:ty),+ $(,)?) => {$(
118+
impl From<$crate::Error<$f>> for $crate::Error<$e> {
119+
fn from(e: $crate::Error<$f>) -> Self {
120+
e.cast()
121+
}
122+
}
123+
)*};
124+
}
125+
19126
/// Checks a condition, logging if it fails.
20127
///
21128
/// If the condition does not hold, constructs the given error, logs it, and
22129
/// returns out of the current function with it.
23130
macro_rules! check {
24131
($cond:expr, $error:expr) => {
25132
if !$cond {
26-
let e = $error;
27-
error!(
28-
"check failure: `{}`; returned {:?}"
29-
stringify!($cond), e
30-
);
31-
return Err(e);
133+
let error = $error;
134+
fail!(
135+
error,
136+
"check failure: `{}`; returned {:?}",
137+
stringify!($cond),
138+
error,
139+
)?;
32140
}
33-
}
141+
};
34142
}
35143

36144
/// Logs a newly-created error value and returns it.
37145
///
38-
/// This function is useful for marking where errors originate in tests.
146+
/// This macro is the main way to generate [`Error`] values.
147+
///
39148
/// For example, instead of writing `foo.ok_or(MyError)`, instead write
40-
/// `foo.ok_or_else(|| trace!(MyError))`.
41-
macro_rules! trace {
149+
/// `foo.ok_or_else(|| fail!(MyError))`.
150+
macro_rules! fail {
42151
($error:expr, $($format:tt)+) => {{
43152
error!($($format)+);
44-
$error
153+
Err($crate::debug::Error::__new($error))
45154
}};
46155
($error:expr) => {{
47-
let e = $error;
48-
error!("generated error: `{:?}`", e);
49-
e
156+
let error = $error;
157+
error!("generated error: `{:?}`", error);
158+
Err($crate::debug::Error::__new(error))
50159
}};
51160
}
52161

162+
/// Redactable version of [`log::trace!()`].
163+
macro_rules! trace {
164+
($($args:tt)*) => {
165+
#[cfg(feature = "log")]
166+
let _ = __raw_log::trace!($($args)*);
167+
}
168+
}
169+
53170
/// Redactable version of [`log::info!()`].
54171
macro_rules! info {
55172
($($args:tt)*) => {
@@ -78,7 +195,7 @@ macro_rules! error {
78195
/// test binary.
79196
///
80197
/// This needs to happen here, since the test binary's main() cannot be
81-
/// overriden.
198+
/// overridden.
82199
#[cfg(test)]
83200
#[ctor::ctor]
84201
fn init_test_logger() {
@@ -90,7 +207,7 @@ fn init_test_logger() {
90207
let name = thread.name().unwrap_or("<unknown>");
91208
for line in record.args().to_string().trim().lines() {
92209
// NOTE: we explicitly print to stderr, since this allows the
93-
// Rust test harness to supress log statements originating from
210+
// Rust test harness to suppress log statements originating from
94211
// passing tests.
95212
eprintln!(
96213
"[{level}({thread}) {file}:{line}] {msg}",

src/hardware/flash.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ impl From<OutOfMemory> for Error {
5858
Error::Internal
5959
}
6060
}
61+
debug_from!(Error => OutOfMemory);
6162

6263
/// Provides access to a flash-like storage device.
6364
///

src/lib.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@
5353
// `debug`.
5454
#[cfg(feature = "log")]
5555
extern crate log as __raw_log;
56+
#[macro_use]
57+
mod debug;
5658

5759
#[macro_use]
5860
pub mod protocol;
59-
#[macro_use]
60-
mod debug;
6161

6262
#[cfg(feature = "serde")]
6363
mod serde;
@@ -71,3 +71,12 @@ pub mod mem;
7171
pub mod net;
7272
pub mod server;
7373
pub mod session;
74+
75+
pub use debug::Error;
76+
77+
/// [`Result`] type to use throughout Manticore, which incorporates the
78+
/// [`manticore::Error`] type.
79+
///
80+
/// [`Result`]: std::result::Result
81+
/// [`manticore::Error`]: crate::Error
82+
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
@@ -274,6 +274,8 @@ impl From<hash::Error> for Error {
274274
}
275275
}
276276

277+
debug_from!(Error => io::Error, flash::Error, OutOfMemory, sig::Error, hash::Error);
278+
277279
/// A manifest type.
278280
///
279281
/// A type that implements this trait is not itself a "parsed" instance of the

src/net/mod.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
/// A header type, which represents a protocol over the wire.
5456
pub trait Header: Copy {
5557
/// The command type enum associated with this header.

src/protocol/cerberus/error.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,80 @@ impl From<session::Error> for Error {
256256
Self::Internal
257257
}
258258
}
259+
260+
impl<E: SpecificError> From<E> for Error<E> {
261+
fn from(e: E) -> Self {
262+
Self::Specific(e)
263+
}
264+
}
265+
266+
debug_from!(Error<E> => OutOfMemory, crypto::csrng::Error, crypto::hash::Error, crypto::sig::Error, session::Error);
267+
debug_from!(Error<E: SpecificError> => E);
268+
269+
/// A type that describes a message-specific error.
270+
///
271+
/// This trait is an implementation detail.
272+
#[doc(hidden)]
273+
pub trait SpecificError: Sized {
274+
/// Converts an error into this error type, if it represents one.
275+
fn from_raw(code: u8) -> Result<Self, wire::Error>;
276+
277+
/// Copies this error into an error code.
278+
fn to_raw(&self) -> Result<u8, wire::Error>;
279+
}
280+
281+
/// An empty [`SpecificError`], for use with messages without interesting error
282+
/// messages.
283+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
284+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
285+
pub enum NoSpecificError {}
286+
impl SpecificError for NoSpecificError {
287+
fn from_raw(_: u8) -> Result<Self, wire::Error> {
288+
Err(wire::Error::OutOfRange)
289+
}
290+
291+
fn to_raw(&self) -> Result<u8, wire::Error> {
292+
match *self {}
293+
}
294+
}
295+
296+
/// Helper for creating specific errors. Compare `wire_enum!`.
297+
macro_rules! specific_error {
298+
(
299+
$(#[$emeta:meta])*
300+
$vis:vis enum $name:ident {$(
301+
$(#[$vmeta:meta])*
302+
$var:ident = $code:literal
303+
),* $(,)*}
304+
) => {
305+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
306+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
307+
$(#[$emeta])*
308+
$vis enum $name {$(
309+
$(#[$vmeta])*
310+
$var,
311+
)*}
312+
313+
impl $crate::protocol::error::SpecificError for $name {
314+
fn from_raw(code: u8) -> Result<Self, $crate::protocol::wire::Error> {
315+
match code {
316+
$($code => Ok(Self::$var),)*
317+
_ => Err($crate::protocol::wire::Error::OutOfRange),
318+
}
319+
}
320+
fn to_raw(&self) -> Result<u8, $crate::protocol::wire::Error> {
321+
match self {$(
322+
Self::$var => Ok($code),
323+
)*}
324+
}
325+
}
326+
};
327+
}
328+
329+
specific_error! {
330+
/// Errors specific to the [`protocol::Challenge`] and related messages.
331+
pub enum ChallengeError {
332+
/// The requested certificate chain does not exist.
333+
UnknownChain = 0x00,
334+
}
335+
}

src/protocol/wire.rs

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

61+
debug_from!(Error => io::Error, OutOfMemory);
62+
6163
/// A type which can be serialized into the Cerberus wire format.
6264
pub trait ToWire: Sized {
6365
/// Serializes `self` into `w`.
@@ -207,7 +209,12 @@ macro_rules! wire_enum {
207209
impl core::str::FromStr for $name {
208210
type Err = $crate::protocol::wire::WireEnumFromStrError;
209211

210-
fn from_str(s: &str) -> Result<Self, $crate::protocol::wire::WireEnumFromStrError> {
212+
fn from_str(
213+
s: &str
214+
) -> core::result::Result<
215+
Self,
216+
$crate::protocol::wire::WireEnumFromStrError
217+
> {
211218
match s {
212219
$(stringify!($variant) => Ok(Self::$variant),)*
213220
_ => Err($crate::protocol::wire::WireEnumFromStrError),

src/server/handler.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ impl<H: net::Header> From<net::Error> for Error<H> {
123123
}
124124
}
125125

126+
debug_from!(Error<H: net::Header> => wire::Error, net::Error);
127+
126128
/// A request handler builder.
127129
///
128130
/// See the module documentation for more information.

0 commit comments

Comments
 (0)