Skip to content

Commit 2246f8b

Browse files
committed
marshal can give better error messages on eof
1 parent a5d4512 commit 2246f8b

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

bytecode/src/lib.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -732,11 +732,38 @@ impl<C: Constant> CodeObject<C> {
732732
}
733733
}
734734

735+
#[derive(Debug)]
736+
#[non_exhaustive]
737+
pub enum CodeDeserializeError {
738+
Eof,
739+
Other,
740+
}
741+
impl fmt::Display for CodeDeserializeError {
742+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
743+
match self {
744+
Self::Eof => f.write_str("unexpected end of data"),
745+
Self::Other => f.write_str("invalid bytecode"),
746+
}
747+
}
748+
}
749+
impl std::error::Error for CodeDeserializeError {}
750+
735751
impl CodeObject<ConstantData> {
736752
/// Load a code object from bytes
737-
pub fn from_bytes(data: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
738-
let raw_bincode = lz4_flex::decompress_size_prepended(data)?;
739-
let data = bincode::deserialize(&raw_bincode)?;
753+
pub fn from_bytes(data: &[u8]) -> Result<Self, CodeDeserializeError> {
754+
use lz4_flex::block::DecompressError;
755+
let raw_bincode = lz4_flex::decompress_size_prepended(data).map_err(|e| match e {
756+
DecompressError::OutputTooSmall { .. } | DecompressError::ExpectedAnotherByte => {
757+
CodeDeserializeError::Eof
758+
}
759+
_ => CodeDeserializeError::Other,
760+
})?;
761+
let data = bincode::deserialize(&raw_bincode).map_err(|e| match *e {
762+
bincode::ErrorKind::Io(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
763+
CodeDeserializeError::Eof
764+
}
765+
_ => CodeDeserializeError::Other,
766+
})?;
740767
Ok(data)
741768
}
742769

vm/src/stdlib/marshal.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,14 @@ mod decl {
2323

2424
#[pyfunction]
2525
fn loads(code_bytes: PyBytesLike, vm: &VirtualMachine) -> PyResult<PyCode> {
26-
let code = bytecode::CodeObject::from_bytes(&*code_bytes.borrow_value())
27-
.map_err(|_| vm.new_value_error("Couldn't deserialize python bytecode".to_owned()))?;
26+
let code =
27+
bytecode::CodeObject::from_bytes(&*code_bytes.borrow_value()).map_err(|e| match e {
28+
bytecode::CodeDeserializeError::Eof => vm.new_exception_msg(
29+
vm.ctx.exceptions.eof_error.clone(),
30+
"end of file while deserializing bytecode".to_owned(),
31+
),
32+
_ => vm.new_value_error("Couldn't deserialize python bytecode".to_owned()),
33+
})?;
2834
Ok(PyCode {
2935
code: vm.map_codeobj(code),
3036
})

0 commit comments

Comments
 (0)