uutils / uutils/diffutils

diff panics (broken-pipe unwrap) when its stdout is closed early

Offen
#244 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Vorherrschende Sprache
Rust
Sterne
276
Forks
39
Ø Merge
3 Std. 27 Min.
Gemergte PRs (30 T.)
3

Beschreibung

Summary

When diff's standard output is a pipe whose reader closes early (e.g. diff … | head), uutils diff aborts with a panic (exit 134, core dump)
instead of dying cleanly to SIGPIPE like GNU (exit 141). The output is written with a bare .unwrap() on the write_all/push_output result; the BrokenPipe error is unwrapped and, under panic="abort", aborts the process. This affects every output mode: the normal/context/unified/ed path writes the buffered result in src/diff.rs:94, and the side-by-side (-y) path writes each line in src/side_diff.rs:353-356.

Steps to reproduce

$ seq 1 100000 > b1; seq 1 100000 | sed 's/5/X/' > b2
$ diffutils diff b1 b2 | head -1
thread 'main' panicked at src/diff.rs:94:41:
called `Result::unwrap()` on an `Err` value: Os { code: 32, kind: BrokenPipe, message: "Broken pipe" }
$ echo "${PIPESTATUS[0]}"
134

Side-by-side mode hits the sibling site src/side_diff.rs:353:

$ diffutils diff -y b1 b2 | head -1
thread 'main' panicked at src/side_diff.rs:353:87:
called `Result::unwrap()` on an `Err` value: Os { code: 32, kind: BrokenPipe, message: "Broken pipe" }
$ echo "${PIPESTATUS[0]}"
134

Expected behavior

Match GNU: a closed output pipe terminates the program via SIGPIPE (exit 141) with no error message and no core dump.

$ /usr/bin/diff b1 b2 | head -1
1c1
$ echo "${PIPESTATUS[0]}"
141
$ /usr/bin/diff -y b1 b2 | head -1
1                            <      1
$ echo "${PIPESTATUS[0]}"
141

Root cause

The full diff output (normal/context/unified/ed) is buffered and written once:

// src/diff.rs:94
io::stdout().write_all(&result).unwrap();

Side-by-side writes each line straight to the locked stdout and unwraps every
write:

// src/side_diff.rs:353-356
push_output(...).unwrap();   // and the sibling unwraps at :354, :356

Any write_all/push_output error — BrokenPipe in the common pipe-closed case — is unwrapped and aborts.

Found by our static analysis tooling.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit den in src/diff.rs:94 und src/side_diff.rs:353-356 identifizierten Ausgabeschreibvorgängen und reproduziere anschließend beide Fälle, normal und nebeneinander, mit den bereitgestellten seq-, sed- und head-Befehlen. Überprüfe, dass die Ausgabe in eine geschlossene Pipe nicht mehr zu einem Panic führt oder einen Fehler ausgibt und dass beide Modi mit dem erwarteten SIGPIPE-Status wie GNU diff beendet werden.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
rust
Bereich
cli
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Ruhig
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
72/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.