cmp: use checked subtraction for the verbose offset padding

The --verbose branch of format_verbose_difference padded the byte-offset
column with a plain subtraction while the --print-bytes branch above it
already used saturating_sub. offset_width is derived from the smaller
file's metadata length, so a file reporting length 0 that still yields
bytes (/dev/zero) collapses it to 2 and the subtraction underflows once
the offset reaches three digits.

Fixes #265
This commit is contained in:
Pablo Garcia authored and Sylvestre Ledru committed 2026-08-18 08:36:39 +02:00
1 parent 3b68237566
commit 68d0610cab
2 files changed
+21 -1

No files matched your search

+1 -1
View File
@@ -607,7 +607,7 @@ fn format_verbose_difference(
} else {
// "{:>width$} {:>3o} {:>3o}"
let at_byte_str = at_byte_buf.format(at_byte);
let at_byte_padding = offset_width - at_byte_str.len();
let at_byte_padding = offset_width.saturating_sub(at_byte_str.len());
for _ in 0..at_byte_padding {
output.push(b' ')
+20
View File
@@ -348,6 +348,26 @@ mod diff {
mod cmp {
use super::*;
// A file whose metadata length is 0 but which still yields bytes (/dev/zero)
// collapses the offset column to two characters, so the padding subtraction
// underflowed once the running offset reached three digits.
#[test]
#[cfg(unix)]
fn cmp_verbose_zero_length_metadata() -> Result<(), Box<dyn std::error::Error>> {
let mut file = NamedTempFile::new()?;
file.write_all(&[0xffu8; 150])?;
let mut cmd = cargo_bin_cmd!("diffutils");
cmd.arg("cmp")
.arg("--verbose")
.arg("/dev/zero")
.arg(file.path());
cmd.assert()
.code(predicate::eq(1))
.stdout(predicate::str::contains("150 0 377"));
Ok(())
}
#[test]
fn cmp_incompatible_params() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = cargo_bin_cmd!("diffutils");