Skip to content

Commit d0dbe7c

Browse files
committed
fix: restore verbose error reporting capabilities when parsing of objects fails.
When `verbose-object-parsing-errors` is enabled, it will now once again provide greater details as to where and why the parsing failed.
1 parent 99a3b25 commit d0dbe7c

File tree

6 files changed

+77
-7
lines changed

6 files changed

+77
-7
lines changed

gix-object/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ serde = ["dep:serde", "bstr/serde", "smallvec/serde", "gix-hash/serde", "gix-act
2525
## details information about the error location will be collected.
2626
## Use it in applications which expect broken or invalid objects or for debugging purposes. Incorrectly formatted objects aren't at all
2727
## common otherwise.
28-
verbose-object-parsing-errors = []
28+
verbose-object-parsing-errors = ["winnow/std"]
2929

3030
[dependencies]
3131
gix-features = { version = "^0.36.0", path = "../gix-features", features = ["rustsha1", "progress"] }

gix-object/src/lib.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,12 @@ pub mod decode {
290290
self.inner.fmt(f)
291291
}
292292
}
293+
294+
impl std::error::Error for Error {
295+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
296+
self.inner.cause().map(|v| v as &(dyn std::error::Error + 'static))
297+
}
298+
}
293299
}
294300

295301
///
@@ -318,14 +324,15 @@ pub mod decode {
318324
}
319325

320326
impl std::fmt::Display for Error {
321-
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
322-
Ok(())
327+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
328+
f.write_str("object parsing failed")
323329
}
324330
}
331+
332+
impl std::error::Error for Error {}
325333
}
326334
pub(crate) use _decode::empty_error;
327335
pub use _decode::{Error, ParseError};
328-
impl std::error::Error for Error {}
329336

330337
/// Returned by [`loose_header()`]
331338
#[derive(Debug, thiserror::Error)]

gix-object/src/tree/ref_iter.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ impl<'a> Iterator for TreeRefIter<'a> {
6767
Some(Ok(entry))
6868
}
6969
None => {
70+
let failing = self.data;
7071
self.data = &[];
71-
let empty = &[] as &[u8];
7272
#[allow(clippy::unit_arg)]
7373
Some(Err(crate::decode::Error::with_err(
74-
winnow::error::ErrMode::from_error_kind(&empty, winnow::error::ErrorKind::Verify),
74+
winnow::error::ErrMode::from_error_kind(&failing, winnow::error::ErrorKind::Verify),
7575
)))
7676
}
7777
}

gix-object/tests/commit/mod.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use crate::fixture_name;
2+
use gix_object::{CommitRef, CommitRefIter};
3+
14
const SIGNATURE: & [u8; 487] = b"-----BEGIN PGP SIGNATURE-----\n\niQEzBAABCAAdFiEEdjYp/sh4j8NRKLX27gKdHl60AwAFAl7q2DsACgkQ7gKdHl60\nAwDvewgAkL5UjEztzeVXlzceom0uCrAkCw9wSGLTmYcMKW3JwEaTRgQ4FX+sDuFT\nLZ8DoPu3UHUP0QnKrUwHulTTlKcOAvsczHbVPIKtXCxo6QpUfhsJQwz/J29kiE4L\nsOd+lqKGnn4oati/de2xwqNGi081fO5KILX75z6KfsAe7Qz7R3jxRF4uzHI033O+\nJc2Y827XeaELxW40SmzoLanWgEcdreXf3PstXEWW77CAu0ozXmvYj56vTviVybxx\nG7bc8lwc+SSKVe2VVB+CCfVbs0i541gmghUpZfMhUgaqttcCH8ysrUJDhne1BLG8\nCrOJIWTwAeEDtomV1p76qrMeqr1GFg==\n=qlSN\n-----END PGP SIGNATURE-----";
25

36
const LONG_MESSAGE: &str = "Merge tag 'thermal-v5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux
@@ -159,6 +162,27 @@ mod method {
159162
}
160163
}
161164

165+
#[test]
166+
fn invalid() {
167+
let fixture = fixture_name("commit", "unsigned.txt");
168+
let partial_commit = &fixture[..fixture.len() / 2];
169+
assert_eq!(
170+
CommitRef::from_bytes(partial_commit).unwrap_err().to_string(),
171+
if cfg!(feature = "verbose-object-parsing-errors") {
172+
"expected `<timestamp>`, `<name> <<email>> <timestamp> <+|-><HHMM>`, `author <signature>`"
173+
} else {
174+
"object parsing failed"
175+
}
176+
);
177+
assert_eq!(
178+
CommitRefIter::from_bytes(partial_commit)
179+
.take_while(Result::is_ok)
180+
.count(),
181+
1,
182+
"we can decode some fields before failing"
183+
);
184+
}
185+
162186
mod from_bytes;
163187
mod iter;
164188
mod message;

gix-object/tests/tag/mod.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
use crate::fixture_name;
12
use gix_date::time::Sign;
2-
use gix_object::{bstr::ByteSlice, Kind, TagRef};
3+
use gix_object::{bstr::ByteSlice, Kind, TagRef, TagRefIter};
34

45
mod method {
56
use gix_object::TagRef;
@@ -115,6 +116,25 @@ KLMHist5yj0sw1E4hDTyQa0=
115116
}
116117
}
117118

119+
#[test]
120+
fn invalid() {
121+
let fixture = fixture_name("tag", "whitespace.txt");
122+
let partial_tag = &fixture[..fixture.len() / 2];
123+
assert_eq!(
124+
TagRef::from_bytes(partial_tag).unwrap_err().to_string(),
125+
if cfg!(feature = "verbose-object-parsing-errors") {
126+
""
127+
} else {
128+
"object parsing failed"
129+
}
130+
);
131+
assert_eq!(
132+
TagRefIter::from_bytes(partial_tag).take_while(Result::is_ok).count(),
133+
4,
134+
"we can decode some fields before failing"
135+
);
136+
}
137+
118138
mod from_bytes {
119139
use gix_object::{bstr::ByteSlice, Kind, TagRef};
120140

gix-object/tests/tree/mod.rs

+19
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,25 @@ mod from_bytes {
107107
Ok(())
108108
}
109109

110+
#[test]
111+
fn invalid() {
112+
let fixture = fixture_name("tree", "definitely-special.tree");
113+
let partial_tree = &fixture[..fixture.len() / 2];
114+
assert_eq!(
115+
TreeRef::from_bytes(partial_tree).unwrap_err().to_string(),
116+
if cfg!(feature = "verbose-object-parsing-errors") {
117+
""
118+
} else {
119+
"object parsing failed"
120+
}
121+
);
122+
assert_eq!(
123+
TreeRefIter::from_bytes(partial_tree).take_while(Result::is_ok).count(),
124+
9,
125+
"we can decode about half of it before failing"
126+
);
127+
}
128+
110129
#[test]
111130
fn special_trees() -> crate::Result {
112131
for (name, expected_entry_count) in [

0 commit comments

Comments
 (0)