dircolors: skip invalid UTF-8 lines instead of truncating the config - #14281
dircolors: skip invalid UTF-8 lines instead of truncating the config#14281alexchen-sys wants to merge 1 commit into
Conversation
|
Did you check that it is compatible with GNU? GNU does not reject invalid unicode at most utils generally. |
|
Yes — checked against GNU 9.4 before opening. The fix does not reject invalid UTF-8: the bad line is skipped, reading continues, exit code stays 0. Output matches GNU byte-for-byte on file and stdin (details and the one single-token edge case are in the Known deviation section above). |
|
Binary size comparison: |
|
GNU testsuite comparison: |
sylvestre
left a comment
There was a problem hiding this comment.
please check against git HEAD for GNU binaries (not sources)
9.4 is too old
- you have a bunch of jobs failing
8e54a98 to
b4e711e
Compare
|
Fixed and pushed, forgot |
| /// Iterate over the lines of a config file. | ||
| /// | ||
| /// GNU dircolors is byte-oriented: it never validates UTF-8 and keeps reading | ||
| /// past a malformed line. A `String`-based parser cannot hold invalid UTF-8, | ||
| /// so this approximates GNU by mapping a line that fails to decode to an | ||
| /// empty line: the parser skips it but still counts it, keeping line numbers | ||
| /// in error messages aligned with the file and avoiding the silent truncation | ||
| /// that `lines().map_while(Result::ok)` caused on `InvalidData`. |
There was a problem hiding this comment.
does it really need 7 lines of comment?
There was a problem hiding this comment.
Fair point — trimmed to 3 lines, kept the essentials.
b4e711e to
fdd15ef
Compare
Signed-off-by: Alex Chen <l46983284@gmail.com>
fdd15ef to
bdf6530
Compare
Problem
dircolorsreads the config viaBufRead::lines().map_while(Result::ok). On a line that is not valid UTF-8,lines()returns anInvalidDataerror andmap_whileends the iteration: every line after the bad one is silently dropped, and the user gets a truncatedLS_COLORSwith exit code 0.GNU dircolors tokenizes the file bytewise, so a line that fails to decode is simply ignored and reading continues. With this config:
Current GNU master prints
LS_COLORS='di=01;31:*.txt=00;32:'and exits 0, while uutils main stops after the first entry.Fix
Read the input bytewise with
split(b'\n')(stripping a trailing\r) and decode each line viaString::from_utf8(...).unwrap_or_default(). A line that fails to decode becomes an empty line: the parser skips it but still counts it, so line numbers in error messages stay aligned with the file. The file and stdin paths share the newconfig_lineshelper.Known deviation
A line that is both single-token and invalid UTF-8 (e.g.
BAD\xffLINEalone) makes GNU exit 1 with "invalid line; missing second token", because its byte tokenizer still sees one token. We normalize such a line to empty and skip it, exiting 0. I don't think this corner justifies byte-tokenizing the parser: the line is malformed either way, and the multi-token case (the realistic one) now matches GNU exactly.Tests
Four new tests in
tests/by-util/test_dircolors.rs:LS_COLORSand successVerified against a dircolors binary built from GNU git master (aea70b2) and the 9.11 release: bad line skipped, exit status 0,
LS_COLORSoutput identical.Same bug class as #12920, where
date -falso silently accepted invalid UTF-8 input (fixed in #14280).