From e2d84e98d514e91e9f4fc2c86e4b83af20f15fda Mon Sep 17 00:00:00 2001 From: weili <541602953@qq.com> Date: Tue, 9 Jun 2026 07:21:31 +0000 Subject: [PATCH] locate: don't panic on a too-short --database file `locate -d ` panicked (slice index underflow, exit 101) when the database file is exactly one byte: `check_db` consumes that byte with `read_exact`, then `read_until(b'\0', ...)` hits EOF and appends nothing, leaving `buf` empty. `&buf[..buf.len() - 1]` then underflows `buf.len() - 1` to `usize::MAX` and slices out of bounds. Strip the trailing nul with `strip_suffix(b"\0")` (falling back to the whole buffer when `read_until` stopped at EOF without one) instead of slicing `buf.len() - 1`. An empty buffer now yields `None` (unrecognized format), so the too-short database is skipped like any other invalid one and locate exits 1 instead of crashing. Adds a regression test. --- src/locate/mod.rs | 6 ++++-- tests/db_tests.rs | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/locate/mod.rs b/src/locate/mod.rs index 3eb399c..9041027 100644 --- a/src/locate/mod.rs +++ b/src/locate/mod.rs @@ -490,8 +490,10 @@ impl DbReader { return None; }; - // drop nul byte when matching - match String::from_utf8_lossy(&buf[..buf.len() - 1]).as_ref() { + // drop the trailing nul byte when matching. `read_until` may stop at EOF + // without one (e.g. a too-short file), so strip it only if present rather + // than slicing `buf.len() - 1`, which underflows when `buf` is empty. + match String::from_utf8_lossy(buf.strip_suffix(b"\0").unwrap_or(&buf)).as_ref() { "LOCATE02" => Some(DbFormat::Locate02), _ => None, } diff --git a/tests/db_tests.rs b/tests/db_tests.rs index 89e949d..609071e 100644 --- a/tests/db_tests.rs +++ b/tests/db_tests.rs @@ -253,3 +253,16 @@ fn test_updatedb_locate_roundtrip() { "locate output did not contain the indexed file: {stdout:?}" ); } + +#[test] +fn test_locate_one_byte_db() { + let dir = tempfile::tempdir().unwrap(); + let db = dir.path().join("db_1byte"); + std::fs::write(&db, b"X").unwrap(); + Command::cargo_bin("locate") + .expect("couldn't find locate binary") + .arg(format!("--database={}", db.display())) + .arg("foo") + .assert() + .code(1); +}