Refuse header/footer Bates numbers that would overflow u64 (#2253)

Found while testing crates/edit/src/lib.rs:445

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
NetterSilver
2026-10-15 02:52:17 -04:00
committed by GitHub
co-authored by Claude Haiku 5.5 Brandon Thomas
parent 76c66b8e9c
commit 2a130abf82
3 changed files with 31 additions and 2 deletions
+4
View File
@@ -136,3 +136,7 @@ real_name = "Alexander Alber"
[people.mtlcl410]
display_name = "mtlcl410"
sync_github_name = false
[people.Silvertree2010]
display_name = "Netter"
sync_github_name = false
+10 -2
View File
@@ -450,18 +450,26 @@ pub fn add_header_footer(doc: &mut Document, pages: &[usize], hf: &HeaderFooter,
u32::MAX
)));
}
// The same goes for Bates numbers: the last selected page must still fit in a u64.
let bates0 = hf.text.iter().find_map(|t| bates_start(t)).unwrap_or(1);
if bates0.checked_add(pages.len().saturating_sub(1) as u64).is_none() {
return Err(EditError::Invalid(format!(
"the Bates start number {bates0} leaves no room for {} pages (Bates numbers stop at {})",
pages.len(),
u64::MAX
)));
}
if replace {
remove_marks(doc, pages, MarkKind::HeaderFooter)?;
}
let all = page_list(doc);
let count = all.len();
let bates0 = hf.text.iter().find_map(|t| bates_start(t)).unwrap_or(1);
for (k, &i) in pages.iter().enumerate() {
let page = &all[i];
let (w, h) = page.display_size(doc);
let number =
u32::try_from(u64::from(hf.start_number) + k as u64).map_err(|_| EditError::Invalid("the header page numbers are too large".into()))?;
let bates = bates0 + k as u64;
let bates = bates0.checked_add(k as u64).ok_or_else(|| EditError::Invalid("the Bates numbers are too large".into()))?;
let size = hf.font_size;
let [top, bottom, left, right] = hf.margins;
let mut body: Vec<u8> = format!("BT\n/PCHelv {} Tf\n{}\n", n(size), rgb(hf.color)).into_bytes();
+17
View File
@@ -115,6 +115,23 @@ fn header_start_number_that_would_wrap_is_refused_without_drawing() {
assert_eq!(marks_present(&doc).len(), 1);
}
#[test]
fn header_bates_start_that_would_overflow_is_refused_without_drawing() {
// A Bates start of u64::MAX has no room for a second page. The run must be refused up front
// instead of overflowing (a panic in debug builds, a wrap to 0 in release builds).
let mut doc = fixture();
let hf = HeaderFooter {
text: [String::new(), String::new(), "<<Bates Number#6#18446744073709551615#A#B>>".into(), String::new(), String::new(), String::new()],
..HeaderFooter::default()
};
let err = add_header_footer(&mut doc, &[0, 1], &hf, false, &cx()).unwrap_err();
assert!(err.to_string().contains("Bates"), "{err}");
assert!(marks_present(&doc).is_empty(), "nothing is drawn when the run is refused");
// A single page still fits the start number itself.
add_header_footer(&mut doc, &[0], &hf, false, &cx()).unwrap();
assert_eq!(marks_present(&doc).len(), 1);
}
#[test]
fn replace_and_remove_restore_the_original_content() {
let mut doc = fixture();