From c9acf5ddd4b3bd50ad433c5f7ffe9189cb630c5a Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Mon, 30 Dec 2024 21:07:45 -0500 Subject: [PATCH] head: fix subtraction underflow with --bytes=-N Fix a subtraction underflow that occurred on `head --bytes=-N` when the input had fewer than `N` bytes. Before this commit, printf "a" | head -c -2 would panic. After this commit, it terminates successfully with no output as expected. --- src/uu/head/src/head.rs | 3 ++- tests/by-util/test_head.rs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/uu/head/src/head.rs b/src/uu/head/src/head.rs index a6bb7b53f..04751fa71 100644 --- a/src/uu/head/src/head.rs +++ b/src/uu/head/src/head.rs @@ -256,6 +256,7 @@ fn catch_too_large_numbers_in_backwards_bytes_or_lines(n: u64) -> Option } } +/// Print to stdout all but the last `n` bytes from the given reader. fn read_but_last_n_bytes(input: &mut impl std::io::BufRead, n: u64) -> std::io::Result<()> { if n == 0 { //prints everything @@ -285,7 +286,7 @@ fn read_but_last_n_bytes(input: &mut impl std::io::BufRead, n: u64) -> std::io:: if total_read <= n { // Fill the ring buffer without exceeding n bytes - let overflow = total_read - n; + let overflow = n - total_read; ring_buffer.extend_from_slice(&buffer[..read - overflow]); } else { // Write the ring buffer and the part of the buffer that exceeds n diff --git a/tests/by-util/test_head.rs b/tests/by-util/test_head.rs index 296d7dab7..1d4b15963 100644 --- a/tests/by-util/test_head.rs +++ b/tests/by-util/test_head.rs @@ -157,6 +157,23 @@ fn test_negative_byte_syntax() { .stdout_is(""); } +#[test] +fn test_negative_bytes_greater_than_input_size_stdin() { + new_ucmd!() + .args(&["-c", "-2"]) + .pipe_in("a") + .succeeds() + .no_output(); +} + +#[test] +fn test_negative_bytes_greater_than_input_size_file() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + at.write_bytes("f", b"a"); + ts.ucmd().args(&["-c", "-2", "f"]).succeeds().no_output(); +} + #[test] fn test_negative_zero_lines() { new_ucmd!()