Summary
Running touch -t <TS> with a timestamp whose character count is 10 or 13 and whose first character is a multi-byte UTF-8 character panics. parse_timestamp dispatches on s.chars().count(), but prepend_century slices s[..2] by bytes; when the leading character is wider than one byte the slice lands inside a character and Rust aborts with a char-boundary panic (exit 134). GNU rejects the same input with invalid date format and exits 1.
Steps to reproduce
$ touch -t '€123456789' /tmp/tf
thread 'main' panicked at src/uu/touch/src/touch.rs:744:29:
byte index 2 is not a char boundary; it is inside '€' ...
$ echo $?
134
Expected behavior
Match GNU: report the error and exit non-zero without crashing.
$ /usr/bin/touch -t '€123456789' /tmp/tf
/usr/bin/touch: invalid date format '€123456789'
$ echo $?
1
Actual behavior
uutils panics with byte index 2 is not a char boundary and aborts with exit code 134, instead of reporting an invalid date format. Triggered when the -t value's character count is 10 or 13 (the lengths routed through century prepending) and its first character is more than 2 bytes wide.
Found by our static analysis tooling.
Summary
Running
touch -t <TS>with a timestamp whose character count is 10 or 13 and whose first character is a multi-byte UTF-8 character panics.parse_timestampdispatches ons.chars().count(), butprepend_centuryslicess[..2]by bytes; when the leading character is wider than one byte the slice lands inside a character and Rust aborts with a char-boundary panic (exit 134). GNU rejects the same input withinvalid date formatand exits 1.Steps to reproduce
Expected behavior
Match GNU: report the error and exit non-zero without crashing.
Actual behavior
uutils panics with
byte index 2 is not a char boundaryand aborts with exit code 134, instead of reporting an invalid date format. Triggered when the-tvalue's character count is 10 or 13 (the lengths routed through century prepending) and its first character is more than 2 bytes wide.Found by our static analysis tooling.