From e47071ca529be6ac0e41d63a48f3ffc9ff851e3a Mon Sep 17 00:00:00 2001 From: Scallop Ye Date: Thu, 11 Apr 2024 18:16:14 +0800 Subject: [PATCH] Do not panic on overlong input or output --- src/error.rs | 5 +++++ src/fmt.rs | 2 ++ src/lib.rs | 14 ++++---------- src/parser.rs | 24 ++++++++++++------------ src/resolver.rs | 8 +++++--- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/error.rs b/src/error.rs index 7920bbc8..d30b4d8a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,6 +17,10 @@ pub(crate) enum ParseErrorKind { /// /// The error index points to the first byte of the address. InvalidIpv6Addr, + /// The input length is greater than [`u32::MAX`]. + /// + /// The error index equals `0`. + OverlongInput, } /// An error occurred when parsing URI references. @@ -63,6 +67,7 @@ impl std::error::Error for ParseError {} pub(crate) enum ResolveErrorKind { NonAbsoluteBase, NonHierarchicalBase, + OverlongOutput, // PathUnderflow, } diff --git a/src/fmt.rs b/src/fmt.rs index e2b7d41c..f2837c22 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -46,6 +46,7 @@ impl Display for ParseError { ParseErrorKind::InvalidOctet => "invalid percent-encoded octet at index ", ParseErrorKind::UnexpectedChar => "unexpected character at index ", ParseErrorKind::InvalidIpv6Addr => "invalid IPv6 address at index ", + ParseErrorKind::OverlongInput => "overlong input at index ", }; write!(f, "{}{}", msg, self.index) } @@ -58,6 +59,7 @@ impl Display for ResolveError { ResolveErrorKind::NonHierarchicalBase => { "resolving non-same-document relative reference against non-hierarchical base URI" } + ResolveErrorKind::OverlongOutput => "overlong output", }; f.write_str(msg) } diff --git a/src/lib.rs b/src/lib.rs index 4be0e22b..a50c9ce0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,15 +134,12 @@ impl Uri { /// # Errors /// /// Returns `Err` if the string does not match - /// the [`URI-reference`] ABNF rule from RFC 3986. + /// the [`URI-reference`] ABNF rule from RFC 3986 or + /// if the input length is greater than [`u32::MAX`]. /// /// You may recover an input [`String`] by calling [`ParseError::into_input`]. /// /// [`URI-reference`]: https://datatracker.ietf.org/doc/html/rfc3986/#section-4.1 - /// - /// # Panics - /// - /// Panics if the input length is greater than [`u32::MAX`]. pub fn parse(input: I) -> Result where I: ToUri, @@ -334,11 +331,8 @@ impl<'i, 'o, T: BorrowOrShare<'i, 'o, str>> Uri { /// /// # Errors /// - /// Returns `Err` if any of the above two **must**s is violated. - /// - /// # Panics - /// - /// Panics if the output length would be greater than [`u32::MAX`]. + /// Returns `Err` if any of the above two **must**s is violated or + /// if the output length would be greater than [`u32::MAX`]. /// /// # Examples /// diff --git a/src/parser.rs b/src/parser.rs index d677b946..b20a714e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -10,9 +10,20 @@ use core::{ type Result = core::result::Result; +/// Returns immediately with an error. +macro_rules! err { + ($index:expr, $kind:ident) => { + return Err(crate::error::ParseError { + index: $index as u32, + kind: crate::error::ParseErrorKind::$kind, + input: (), + }) + }; +} + pub(crate) fn parse(bytes: &[u8]) -> Result { if bytes.len() > u32::MAX as usize { - panic!("input length > u32::MAX"); + err!(0, OverlongInput); } let mut parser = Parser { @@ -23,17 +34,6 @@ pub(crate) fn parse(bytes: &[u8]) -> Result { Ok(parser.out) } -/// Returns immediately with an error. -macro_rules! err { - ($index:expr, $kind:ident) => { - return Err(crate::error::ParseError { - index: $index as u32, - kind: crate::error::ParseErrorKind::$kind, - input: (), - }) - }; -} - /// URI parser. /// /// # Invariants diff --git a/src/resolver.rs b/src/resolver.rs index 8fb738ee..0c9e6391 100644 --- a/src/resolver.rs +++ b/src/resolver.rs @@ -128,9 +128,11 @@ pub(crate) fn resolve( buf.push_str(fragment.as_str()); } - assert!(buf.len() <= u32::MAX as usize, "output length > u32::MAX"); - - Ok(Uri { val: buf, meta }) + if buf.len() <= u32::MAX as usize { + Ok(Uri { val: buf, meta }) + } else { + Err(ResolveError(ResolveErrorKind::OverlongOutput)) + } } /// Removes dot segments from an absolute path.