blob: d014be80d173fd04271aa3d67ab694a157a92255 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Errors that the parser might return. User-visible.
//! FOR_RELEASE: Docs
pub type ParsingResult<T> = Result<T, ParsingError>;
impl std::error::Error for ParsingError {}
#[derive(Debug)]
pub struct ParsingError {
/// The number of bytes from the beginning of the message at which the error
/// occurred.
pub offset: usize,
pub ty: ParsingErrorType,
}
#[derive(Debug)]
pub enum ParsingErrorType {
/// Indicates that we ran out of data while parsing
NotEnoughData {
/// A description of what we tried to parse (a type, or padding, etc)
tried_to_parse: String,
expected_size: usize,
/// How much data was actually left
remaining_bytes: usize,
},
/// Indicates that there was data left over after we finished parsing
TooMuchData { remaining_bytes: usize },
/// Indicates a pointer that was either too small, too large to fit into a
/// usize, unexpectedly null, or not divisible by 8 (so the pointed-to data
/// wouldn't be aligned)
InvalidPointer { value: u64 },
/// Indicates that a nested field wasn't at the pointed-to location
WrongPointer { expected_offset: usize, actual_offset: usize },
/// Indicates a size (as encoded in a struct/array header) was either too
/// small, too large to fit into a usize, or not divisible by 8.
InvalidSize { value: u32 },
/// Indicates that a struct or array had more bytes than its header claimed
WrongSize { expected_size: usize, actual_size: usize },
}
impl ParsingError {
pub fn not_enough_data(
offset: usize,
tried_to_parse: String,
expected_size: usize,
remaining_bytes: usize,
) -> ParsingError {
ParsingError {
offset,
ty: ParsingErrorType::NotEnoughData { tried_to_parse, expected_size, remaining_bytes },
}
}
pub fn too_much_data(offset: usize, remaining_bytes: usize) -> ParsingError {
ParsingError { offset, ty: ParsingErrorType::TooMuchData { remaining_bytes } }
}
pub fn invalid_pointer(offset: usize, value: u64) -> ParsingError {
ParsingError { offset, ty: ParsingErrorType::InvalidPointer { value } }
}
pub fn invalid_size(offset: usize, value: u32) -> ParsingError {
ParsingError { offset, ty: ParsingErrorType::InvalidSize { value } }
}
pub fn wrong_pointer(
offset: usize,
expected_offset: usize,
actual_offset: usize,
) -> ParsingError {
ParsingError {
offset,
ty: ParsingErrorType::WrongPointer { expected_offset, actual_offset },
}
}
pub fn wrong_size(offset: usize, expected_size: usize, actual_size: usize) -> ParsingError {
ParsingError { offset, ty: ParsingErrorType::WrongSize { expected_size, actual_size } }
}
}
// These messages necessarily refer to details of the binary format, and so they
// are mostly suitable for debugging, not for end-users (who don't really care
// why a message was invalid, since it should never happen unless a parser/
// deparser is misbehaving).
impl std::fmt::Display for ParsingError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"An error occurred at byte {} when parsing the message. Details:\n",
self.offset
)?;
match &self.ty {
ParsingErrorType::NotEnoughData { tried_to_parse, expected_size, remaining_bytes } => {
write!(
f,
"Tried to parse {tried_to_parse} ({expected_size} bytes), \
but only {remaining_bytes} bytes remained."
)
}
ParsingErrorType::TooMuchData { remaining_bytes } => {
write!(f, "There were {remaining_bytes} bytes remaining after parsing finished.")
}
ParsingErrorType::InvalidPointer { value } => {
if *value < 8 {
write!(f, "Pointer value {value} is less than its own size (8).")
} else if *value % 8 != 0 {
write!(
f,
"Pointer value {value} points to unaligned data \
(because it is not divisible by 8)."
)
} else {
write!(f, "Pointer value {value} doesn't fit into 64 bits.")
}
}
ParsingErrorType::InvalidSize { value } => {
if *value < 8 {
write!(f, "Size value {value} is less than the size of a header(8).")
} else if *value % 8 != 0 {
write!(f, "Size value {value} is not divisible by 8.")
} else {
write!(f, "Pointer value {value} doesn't fit into 32 bits.")
}
}
ParsingErrorType::WrongPointer { expected_offset, actual_offset } => {
write!(
f,
"Expected to find a nested field at {expected_offset} bytes from the \
beginning of the struct, but it was actually at {actual_offset} bytes."
)
}
ParsingErrorType::WrongSize { expected_size, actual_size } => {
write!(
f,
"Struct/Array claimed to have {expected_size} bytes, \
but we parsed {actual_size} bytes."
)
}
}
}
}