Skip to content

Quoted() does not escape backslashes, corrupting process arguments #2796

Open

Description

@drewster99

Summary

StringExtensions.Quoted() (src/App.Extensions.cs) wraps a value in double quotes and escapes embedded ", but leaves backslashes untouched. Its result is assigned to ProcessStartInfo.Arguments, which .NET re-parses into argv using MSVC-style rules on every platform, where a backslash immediately before a double quote is significant.

As a result, a value that ends in a backslash, or contains a backslash directly before a quote, is handed to the child process (git) as a different string than the input.

Impact

A file whose name ends in a backslash is legal on macOS and Linux. Such a path reaches commands that place the filename last with no --, e.g.:

  • src/Commands/QueryFileContent.cs — show {rev}:{file}
  • src/Commands/SaveRevisionFile.cs — show {rev}:{file}
  • src/Commands/QueryFileSize.cs — cat-file -s {rev}:{file}

Viewing or saving that file from history then operates on the wrong path or fails. Two-argument commands such as Move (mv -v {old} {new}) can have the first path swallow the second.

This is a data-integrity / quoting-correctness bug. It is not a shell: arguments are passed via UseShellExecute = false, so no shell metacharacters are involved.

Reproduction

Round-trip the current Quoted() output through .NET's own argument parser:

input Quoted() output parsed back to
trailing\ "trailing\" trailing"
a\"b.txt "a\\"b.txt" a\b.txt

Plain names, names with spaces, and a lone embedded quote round-trip correctly.

Suggested fix

Escape the value the same way .NET itself does when building an argument (System.PasteArguments): double any run of backslashes that precedes a quote or the closing quote. This fixes every call site at once, since they all funnel through Quoted() into Args.

A PR implementing this, with a standalone round-trip test that checks the invariant against .NET's real argument parser, follows.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions