Mercurial > hg
changeset 50536:475c170bb815
dirstate: better error messages when dirstate is corrupted
The current error message "Overflow in dirstate" sounds confusing
because it suggests either a certain size limit that's being exceeded,
or integer arithmetic overflowing. The reality is just a file being shorter
than expected.
author | Arseniy Alekseyev <aalekseyev@janestreet.com> |
---|---|
date | Wed, 31 May 2023 19:00:11 +0100 |
parents | a8531bd9210b |
children | 6a019a037085 |
files | rust/hg-core/src/dirstate/parsers.rs |
diffstat | 1 files changed, 20 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/hg-core/src/dirstate/parsers.rs Wed May 31 18:18:52 2023 +0100 +++ b/rust/hg-core/src/dirstate/parsers.rs Wed May 31 19:00:11 2023 +0100 @@ -61,12 +61,21 @@ Option<&'a HgPath>, ) -> Result<(), HgError>, ) -> Result<&'a DirstateParents, HgError> { - let (parents, rest) = DirstateParents::from_bytes(contents) - .map_err(|_| HgError::corrupted("Too little data for dirstate."))?; + let mut entry_idx = 0; + let original_len = contents.len(); + let (parents, rest) = + DirstateParents::from_bytes(contents).map_err(|_| { + HgError::corrupted(format!( + "Too little data for dirstate: {} bytes.", + original_len + )) + })?; contents = rest; while !contents.is_empty() { let (raw_entry, rest) = RawEntry::from_bytes(contents) - .map_err(|_| HgError::corrupted("Overflow in dirstate."))?; + .map_err(|_| HgError::corrupted(format!( + "dirstate corrupted: ran out of bytes at entry header {}, offset {}.", + entry_idx, original_len-contents.len())))?; let entry = DirstateEntry::from_v1_data( EntryState::try_from(raw_entry.state)?, @@ -74,9 +83,14 @@ raw_entry.size.get(), raw_entry.mtime.get(), ); + let filename_len = raw_entry.length.get() as usize; let (paths, rest) = - u8::slice_from_bytes(rest, raw_entry.length.get() as usize) - .map_err(|_| HgError::corrupted("Overflow in dirstate."))?; + u8::slice_from_bytes(rest, filename_len) + .map_err(|_| + HgError::corrupted(format!( + "dirstate corrupted: ran out of bytes at entry {}, offset {} (expected {} bytes).", + entry_idx, original_len-contents.len(), filename_len)) + )?; // `paths` is either a single path, or two paths separated by a NULL // byte @@ -87,6 +101,7 @@ let copy_source = iter.next().map(HgPath::new); each_entry(path, &entry, copy_source)?; + entry_idx += 1; contents = rest; } Ok(parents)