Skip to content

od: preserve non-UTF-8 file operands - #15242

Open
ozenyunus35 wants to merge 3 commits into
uutils:mainfrom
ozenyunus35:fix/od-non-utf8-operands
Open

ozenyunus35 wants to merge 3 commits into
uutils:mainfrom
ozenyunus35:fix/od-non-utf8-operands

Conversation

@ozenyunus35

@ozenyunus35 ozenyunus35 commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #12794.

od currently drops command-line arguments that are not valid UTF-8. When such an argument is a filename, od behaves as if no file was provided and falls back to reading standard input.

This can cause od to wait for input unexpectedly or read unrelated data instead of reporting a missing file.

Changes

  • Preserve file operands as OsString throughout argument parsing and file handling.
  • Pass the original arguments to clap instead of silently discarding non-UTF-8 values.
  • Keep filenames intact when passing them to File::open.
  • Only interpret operands as offsets or labels when they contain valid UTF-8.
  • Preserve existing behavior for normal filenames and standard input.

Testing

Added two regression tests:

  • A missing non-UTF-8 filename must produce a file error instead of reading stdin.
  • On Linux, an existing file with a non-UTF-8 filename must be read correctly.

The first test fails before the fix and passes afterward.

Validation performed on macOS:

  • test_od: 75 passed.
  • uu_od unit tests: 55 passed.
  • cargo fmt --check: passed.
  • Clippy with -D warnings: passed.
  • CSpell: passed.

The Linux-specific filesystem test could not be executed on macOS and will be exercised by Linux CI.

Compatibility

The change is limited to od argument and file handling. Existing behavior for valid UTF-8 filenames, standard input, and offsets is preserved.

AI Assistance

Claude Code was used to assist with implementation and testing.

od collected its arguments with `collect_ignore()`, which silently drops
every argument that is not valid UTF-8. Such a file operand was lost, so
`od $'\xff'` read standard input (and hung on a terminal) instead of
dumping the file or reporting that it does not exist.

Pass the raw arguments to clap and keep file operands as `OsString`
all the way to `File::open`. Offsets and labels are still parsed from
operands that are valid UTF-8.

Fixes uutils#12794
Comment thread tests/by-util/test_od.rs

let (at, mut ucmd) = at_and_ucmd!();
let name = OsStr::from_bytes(b"\xff");
std::fs::write(at.plus(name), "abcdefghijklmnopqrstuvwxyz\n").unwrap();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to user at.write(file, content) here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I'm missing something that doesn't work because name is an OsStr whereas at.write expects a &str.

@RenjiSann

RenjiSann commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

The tests you added are broken in web-assembly, hence the CI fails.

I suggest setting the tests' cfgs to

#[cfg(not(any(target_os = "wasi", windows)))]

wasmtime cannot pass an argument that is not valid UTF-8 to the
utility, so these tests cannot run there. Mark them like the other
tests that depend on non-UTF-8 arguments.
@ozenyunus35

Copy link
Copy Markdown
Contributor Author

Thanks for the review! I updated the tests in 36237d8.

I used the repository's existing wasi_runner convention because these tests are compiled for the host and execute the utility through Wasmtime. The WASI jobs are now passing.

Regarding at.write, the filename is an OsStr and may contain invalid UTF-8, whereas at.write expects a &str, as cakebaker pointed out.

Comment thread src/uu/od/src/multifile_reader.rs Outdated
show_error!(
"{}: {}",
self.file_name.unwrap_or("I/O"),
self.file_name.map_or("I/O".into(), OsStr::to_string_lossy),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could use maybe_quote() here like the open error above, no?

Comment thread tests/by-util/test_od.rs
.pipe_in("not read")
.succeeds()
.stdout_only(unindent(ALPHA_OUT));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please also add a test with an offset, e.g. od --traditional <non-utf8> 10?

@ozenyunus35

Copy link
Copy Markdown
Contributor Author

@sylvestre done in 4482a3a: the read error now uses maybe_quote() like the open error, and I added a test with an offset (od --traditional -c <non-utf8> 10). It's Linux-only like the other non-UTF-8 test.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(od): when $'\xff' the tools hangs while the gnu one rejects it with an error

4 participants