Skip to content

printf: reject malformed hex and unicode escapes in %b arguments - #14406

Open
zfaustk wants to merge 1 commit into
uutils:mainfrom
zfaustk:fix-printf-b-escapes
Open

printf: reject malformed hex and unicode escapes in %b arguments#14406
zfaustk wants to merge 1 commit into
uutils:mainfrom
zfaustk:fix-printf-b-escapes

Conversation

@zfaustk

@zfaustk zfaustk commented Sep 6, 2026

Copy link
Copy Markdown

In %b arguments, malformed \x, \u, and \U escape sequences were previously swallowed by parse_escape_only, printing a literal \x and exiting 0 while dropping consumed characters in \u and \U.

Make parse_escape_only return Result<EscapedChar, FormatError> and propagate errors from %b argument parsing so printf reports missing hex numbers and invalid universal character names with exit code 1 to match GNU coreutils. Also ensure parse_unicode only consumes input when hex digits are present.

Fixes #14404

In %b arguments, malformed \x, \u, and \U escape sequences were previously
swallowed by parse_escape_only, printing a literal \x and exiting 0 while
dropping consumed characters in \u and \U.

Make parse_escape_only return Result<EscapedChar, FormatError> and propagate
errors from %b argument parsing so printf reports missing hex numbers and
invalid universal character names with exit code 1 to match GNU coreutils.
Also ensure parse_unicode only consumes input when hex digits are present.

Fixes uutils#14404
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/timeout/timeout-group (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/tail/tail-n0f (passes in this run but fails in the 'main' branch)
Congrats! The gnu test tests/tail/pipe-f is now passing!

@sylvestre

Copy link
Copy Markdown
Contributor

some jobs are failing

@SichenLiang

Copy link
Copy Markdown

Hi — thanks for turnin so fast!

Moving *input = rest to after the hex parse is the right fix for the character
loss, and I can confirm that part works.

Two things came up testing your branch against GNU 9.7:

Output produced before the bad escape is dropped. GNU writes everything it
converted up to the offending escape and then diagnoses:

$ printf '%s|%b' first 'bad\x'
gnu       first|bad      exit 1
main      first|bad\x    exit 0
this PR   first|         exit 1

It scales with the argument — with 100,000 As followed by \x, GNU writes
100,000 bytes and exits 1, this branch writes 0 and exits 1. Same when stdout is
a file, so it isn't buffering.

Out-of-range \U now errors where main matched GNU. GNU passes it through
and exits 0:

$ printf '%b' '[\U00110000]'
gnu       [\U00110000]   exit 0
main      [\x]           exit 0
this PR   (nothing)      exit 1, invalid universal character name \U00110000

Same for \UFFFFFFFF. main's stdout was wrong there too, but its exit status
agreed with GNU and now it doesn't.

The %b diagnostics themselves are exactly right — it's only what happens to the
bytes before them.

Separately, and not from this change: uutils' echo -e interprets \u/\U where GNU's doesn't at all -- echo -e '[\u0041]'
gives [A] here and [\u0041] on GNU. That's pre-existing, so I'll open a
separate issue for it rather than widen this PR.

Measured on GNU coreutils 9.7 (Ubuntu 26.04) against 71a9079, LC_ALL=C.

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.

printf: a malformed \u or \U in a %b argument drops characters and exits 0

3 participants