Skip to main content

tor_bytes/
err.rs

1//! Internal: Declare an Error type for tor-bytes
2
3use std::borrow::Cow;
4use std::num::NonZeroUsize;
5
6use derive_deftly::{Deftly, define_derive_deftly};
7use safelog::Sensitive;
8use thiserror::Error;
9use tor_error::{Bug, into_internal};
10
11define_derive_deftly! {
12    /// `impl PartialEq for Error`
13    PartialEqForError expect items:
14
15    impl PartialEq for $ttype {
16        fn eq(&self, other: &Self) -> bool {
17            match (self, other) {
18              $(
19                ${when not(vmeta(never_eq))}
20                #[allow(deprecated)]
21                (${vpat fprefix=a_}, ${vpat fprefix=b_}) => {
22                  $(
23                    if $<a_ $fname> != $<b_ $fname> { return false; }
24                  )
25                    return true;
26                },
27              )
28                (_, _) => false,
29            }
30        }
31    }
32}
33
34/// Error type for decoding Tor objects from bytes.
35//
36// TODO(nickm): This error type could use a redesign: it doesn't do a good job
37// of preserving context.  At the least it should say what kind of object it
38// found any given problem in.
39#[derive(Error, Debug, Clone, Deftly)]
40#[derive_deftly(PartialEqForError)]
41#[non_exhaustive]
42pub enum Error {
43    /// Something was truncated
44    ///
45    /// It might be an inner data structure, or the outer message being parsed.
46    #[deprecated(since = "0.22.0", note = "Use Reader::incomplete_error instead.")]
47    #[error("something was truncated (maybe inner structure, maybe outer message)")]
48    Truncated,
49    /// Tried to read something, but we didn't find enough bytes.
50    ///
51    /// This can means that the outer object is truncated.
52    /// Possibly we need to read more and try again,
53    ///
54    /// This error is only returned by [`Reader`](crate::Reader)s created with
55    /// [`from_possibly_incomplete_slice`](crate::Reader::from_possibly_incomplete_slice).
56    ///
57    /// # Do not directly construct this variant
58    ///
59    /// It is usually a bug to explicitly construct this variant.
60    /// Use [`Reader::incomplete_error`](crate::Reader::incomplete_error) instead.
61    ///
62    /// In tests using
63    /// [`Reader::from_slice_for_test`](crate::Reader::from_slice_for_test),
64    /// use [`Error::new_incomplete_for_test`].
65    #[error("Object truncated (or not fully present), at least {deficit} more bytes needed")]
66    Incomplete {
67        /// Lower bound on number of additional bytes needed
68        deficit: Sensitive<NonZeroUsize>,
69    },
70    /// Called Reader::should_be_exhausted(), but found bytes anyway.
71    #[error("Extra bytes at end of object")]
72    ExtraneousBytes,
73    /// Invalid length value
74    #[error("Object length too large to represent as usize")]
75    BadLengthValue,
76    /// An attempt to parse an object failed for some reason related to its
77    /// contents.
78    #[deprecated(since = "0.6.2", note = "Use InvalidMessage instead.")]
79    #[error("Bad object: {0}")]
80    BadMessage(&'static str),
81    /// An attempt to parse an object failed for some reason related to its
82    /// contents.
83    ///
84    /// # General case, more specific variants also exist
85    ///
86    /// This variant is used when encountering parsing trouble
87    /// for which there is no more specific variant.
88    ///
89    /// Other variants can occur when deserialising malformed messages.
90    /// for example (but not necessarily only):
91    /// [`ExtraneousBytes`](Error::ExtraneousBytes),
92    /// [`MissingData`](Error::MissingData), and
93    /// [`BadLengthValue`](Error::BadLengthValue).
94    #[error("Bad object: {0}")]
95    InvalidMessage(Cow<'static, str>),
96    /// The message contains data which is too short (perhaps in an inner counted section)
97    ///
98    /// # Usually, do not directly construct this variant
99    ///
100    /// It is often a bug to explicitly construct this variant.
101    /// Consider [`Reader::incomplete_error`](crate::Reader::incomplete_error) instead.
102    ///
103    /// (It can be appropriate in test cases,
104    /// or during bespoke parsing of an inner substructure.)
105    #[error("message (or inner portion) too short")]
106    MissingData,
107    /// A parsing error that should never happen.
108    ///
109    /// We use this one in lieu of calling assert() and expect() and
110    /// unwrap() from within parsing code.
111    #[error("Internal error")]
112    #[deftly(never_eq)] // an internal error is equal to nothing, not even itself.
113    Bug(#[from] tor_error::Bug),
114    /// Using for reader.rs::take_until_with_limit
115    /// If we reach the limit before finding the terminator, we return this error.
116    #[error("Reached limit of {limit} bytes while searching for terminator 0x{terminator:02x}")]
117    LimitExceeded {
118        /// Maximum number of bytes that were allowed to read
119        limit: usize,
120        /// The terminator byte we were looking for
121        terminator: u8,
122    },
123}
124
125impl Error {
126    /// Make an [`Error::Incomplete`] with a specified deficit
127    ///
128    /// Suitable for use in tests.
129    ///
130    /// # Panics
131    ///
132    /// Panics if the specified `deficit` is zero.
133    pub fn new_incomplete_for_test(deficit: usize) -> Self {
134        let deficit = NonZeroUsize::new(deficit)
135            .expect("zero deficit in assert!")
136            .into();
137        Error::Incomplete { deficit }
138    }
139}
140
141/// Error type for encoding Tor objects to bytes.
142#[derive(Error, Debug, Clone)]
143#[non_exhaustive]
144pub enum EncodeError {
145    /// We tried to encode an object with an attached length, but the length was
146    /// too large to encode in the available space.
147    #[error("Object length too large to encode")]
148    BadLengthValue,
149    /// A parsing error that should never happen.
150    ///
151    /// We use this variant instead of calling assert() and expect() and
152    /// unwrap() from within encoding implementations.
153    #[error("Internal error")]
154    Bug(#[from] Bug),
155}
156
157impl EncodeError {
158    /// Converts this error into a [`Bug`]
159    ///
160    /// Use when any encoding error is a bug.
161    //
162    // TODO: should this be a `From` impl or would that be too error-prone?
163    #[deprecated(note = "please use the `From<EncodeError>` trait for `Bug` instead")]
164    pub fn always_bug(self) -> Bug {
165        match self {
166            EncodeError::Bug(bug) => bug,
167            EncodeError::BadLengthValue => into_internal!("EncodingError")(self),
168        }
169    }
170}
171
172// This trait is used to convert any encoding error into a bug
173impl From<EncodeError> for Bug {
174    fn from(error: EncodeError) -> Bug {
175        match error {
176            EncodeError::Bug(bug) => bug,
177            EncodeError::BadLengthValue => into_internal!("EncodingError")(error),
178        }
179    }
180}