fix(cli): reject -j 0 instead of silently falling through to serial
`--threads` was an `Option<usize>` with no value-parser bound. Passing
`-j 0` slipped past clap and reached the dispatch in `crypto::encrypt`
/ `decrypt`, where the `threads > 1` check evaluates to false for 0 and
the call quietly fell through to the serial path. The user thought
they had asked for "no worker threads" and got something else instead;
either way, 0 workers is not a meaningful configuration.
Switch the field to `Option<u32>` and add `value_parser!(u32).range(1..)`
so clap rejects `-j 0` at parse time with a usage error. Cast to
`usize` at the single use site. Using `u32` rather than `usize` avoids
shipping a host-pointer-width-dependent CLI surface; thread counts well
past 4 billion are not a thing we need to plan for.
Test plan:
- New integration test `rejects_zero_threads` invokes the binary
with `-j 0` and asserts non-zero exit.
- Existing `roundtrip_multi_threaded` (`-j 4`) still passes, so the
range bound has not broken normal usage.
Refs: external review (GLM51 #1; Gemini #3 misdescribed the symptom
as "silent corruption" — verified the actual behaviour was a fall-
through to the serial path, not output corruption, but the fix is
the same).
This commit is contained in:
@@ -723,6 +723,27 @@ fn random_access_tampered_length_fails() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_zero_threads() {
|
||||
// -j 0 is almost certainly a user mistake. Clap should reject it before
|
||||
// we ever reach the pipeline.
|
||||
let dir = TempDir::new().unwrap();
|
||||
let plain = dir.path().join("p.bin");
|
||||
fs::write(&plain, b"hello").unwrap();
|
||||
let out = fcry()
|
||||
.arg("-i")
|
||||
.arg(&plain)
|
||||
.arg("-o")
|
||||
.arg(dir.path().join("c.bin"))
|
||||
.arg("--raw-key")
|
||||
.arg(KEY_STR)
|
||||
.arg("-j")
|
||||
.arg("0")
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(!out.status.success(), "-j 0 should be rejected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn header_chunk_size_is_authoritative_on_decrypt() {
|
||||
// Encrypt with a non-default chunk size; decrypt without specifying one.
|
||||
|
||||
Reference in New Issue
Block a user