Skip to content

fix: escape more stuff in quoted filenames - #42

Merged
weihanglo merged 4 commits into
git-format-patchfrom
fix
Apr 7, 2026
Merged

fix: escape more stuff in quoted filenames #42
weihanglo merged 4 commits into
git-format-patchfrom
fix

Conversation

@weihanglo

@weihangloweihanglo commented Apr 7, 2026

Copy link
Copy Markdown
Owner

diffy currently rejects \a, \b, \f, \v, and \0 as InvalidEscapedChar.
Both git apply and GNU patch decode them.

Observed with git 2.53.0:

$ printf'x'>"$(printf 'f\x07')"&& git add -A
$ git diff --cached --name-only"f\a"

Observed with GNU patch 2.7.1:

$ patch -p0 < test.patch # with +++ "bel\a"patching file bel<BEL>

Observed with git 2.53.0:

$ printf'x'>"$(printf 'f\033')"&& git add -A
$ git diff --cached | grep '+++'+++ "b/f\033"

GNU patch 2.7.1 also decodes \033 correctly. It segfaults on malformed
\0 followed by non-octal digits, confirming \0 is never a standalone escape.

Previously, _escaped_filename() treated \0 as standalone NUL (0x00), so \033 was misparsed as NUL + literal "33". This produced filenames with embedded NUL bytes, which are invalid on all major filesystems.

We now replace the b'0' => b'\0' arm with a 3-digit octal parser to match the observed git and GNU patch behavior: first digit 0–3, followed by exactly two octal digits 0–7.

See also https://git-scm.com/docs/git-config#Documentation/git-config.txt-corequotePath

diffy currently rejects `\a`, `\b`, `\f`, `\v` as `InvalidEscapedChar`.
Both git apply and GNU patch decode them.
Observed with git 2.53.0:
```console
$ printf 'x' > "$(printf 'f\x07')" && git add -A
$ git diff --cached --name-only
"f\a"
```
Observed with GNU patch 2.7.1:
```console
$ patch -p0 < test.patch # with +++ "bel\a"
patching file bel<BEL>
```
@weihangloweihanglo mentioned this pull request Apr 7, 2026
24 tasks
@weihanglo
weihangloforce-pushed the fix branch 2 times, most recently from cb7be49 to 819eff7CompareApril 7, 2026 05:31
Diffy misparsed `\0` as standalone NUL instead of
the start of a 3-digit octal sequence,
so `\033` becomes NUL + "33".
Both git apply and GNU patch decode `\033` as ESC (0x1B).
Observed with git 2.53.0:
```
$ printf 'x' > "$(printf 'f\033')" && git add -A
$ git diff --cached | grep '+++'
+++ "b/f\033"
```
Observed with GNU patch 2.7.1:
```
$ patch -p1 < test.patch # with +++ "b/tl\033"
patching file tl<ESC>
```
Found via llvm/llvm-project full-history replay
(commits 17af06ba..229c95ab, 6c031780..0683a1e5).
Note that compat test is not added here and deferred
because misparsed NUL path panics the test harness at filesystem level.
Git uses C-style named escapes for certain control characters in
quoted filenames. Observed with git 2.53.0 and GNU patch 2.7.1:
```console
$ printf 'x' > "$(printf 'f\x07')" && git add -A
$ git diff --cached --name-only
"f\a"
```
```console
$ patch -p0 < test.patch # with +++ "bel\a"
patching file bel<BEL>
```
Git encodes bytes without a named escape as 3-digit octal sequences.
Observed with git 2.53.0:
```console
$ printf 'x' > "$(printf 'f\033')" && git add -A
$ git diff --cached | grep '+++'
+++ "b/f\033"
```
GNU patch 2.7.1 also decodes `\033` correctly.
It segfaults on malformed `\0` followed by non-octal digits,
confirming `\0` is never a standalone escape.
Previously,
`_escaped_filename()` treated `\0` as standalone NUL (0x00),
so `\033` was misparsed as NUL + literal "33".
This produced filenames with embedded NUL bytes,
which are invalid on all major filesystems.
We now replace the `b'0' => b'\0'` arm with a 3-digit octal parser
to match the observed git and GNU patch behavior:
first digit 0–3, followed by exactly two octal digits 0–7.
Found via full-history replay test against llvm/llvm-project
(commits 17af06ba..229c95ab, 6c031780..0683a1e5).
@weihanglo
weihanglo merged commit 1113044 into git-format-patchApr 7, 2026
12 checks passed
@weihanglo
weihanglo deleted the fix branch April 7, 2026 05:38
Sign up for freeto 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.

1 participant

@weihanglo