@leroysheep / CrazyWebTemps / commits / 1a2aca2be4

sub-process: add a gentle status read

subprocess_read_status() reads "status=<key>" packets up to a flush with packet_read_line_gently(), which is gentle only about EOF. A malformed length header still dies inside pkt-line, and an empty packet is indistinguishable from the flush that ends the section. A protocol violation in a status section therefore either kills the whole command or silently truncates the section. That posture fits the filter protocol's callers, which treat their process as required infrastructure; the diff process consult added later in this series treats its process as optional, and any protocol error must degrade to the builtin diff rather than abort the command. Add subprocess_read_status_gently(): the same status loop, reading through packet_read_with_status() with the gentle options, returning -1 on a truncated or malformed packet and on an empty packet where a status line or the terminating flush belongs. subprocess_read_status() and its callers are unchanged. The handshake has its gentle counterpart in 061a68e443 (sub-process: use gentle handshake to avoid die() on startup failure, 2026-06-01), which turned truncated handshake reads into error returns for every caller. This series' base includes that commit, so a process that dies during the handshake feeds the same non-fatal fallback as a status failure here, and an optional diff process degrades to the builtin diff on either kind of protocol error. Signed-off-by: Michael Montalbo <mmontalbo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Montalbo committed Aug 1, 2026 at 10:41 UTC 1a2aca2be48f9ea3f54005bbc7a65e087b34937a
2 files changed +34
sub-process.c
+24
index 3cef42b088..33bd789618 100644 --- a/sub-process.c +++ b/sub-process.c @@ -49,6 +49,30 @@ int subprocess_read_status(int fd, struct strbuf *status) return (len < 0) ? len : 0; } +int subprocess_read_status_gently(int fd, struct strbuf *status) +{ + for (;;) { + int pktlen = -1; + enum packet_read_status rs; + const char *value; + + rs = packet_read_with_status(fd, NULL, NULL, packet_buffer, + sizeof(packet_buffer), &pktlen, + PACKET_READ_CHOMP_NEWLINE | + PACKET_READ_GENTLE_ON_EOF | + PACKET_READ_GENTLE_ON_READ_ERROR); + if (rs == PACKET_READ_FLUSH) + return 0; + if (rs != PACKET_READ_NORMAL || !pktlen) + return -1; + if (skip_prefix(packet_buffer, "status=", &value)) { + /* the last "status=<foo>" line wins */ + strbuf_reset(status); + strbuf_addstr(status, value); + } + } +} + void subprocess_stop_command(struct subprocess_entry *entry) { if (!entry)
sub-process.h
+10
index 45f1b8e5e3..8655b38897 100644 --- a/sub-process.h +++ b/sub-process.h @@ -101,4 +101,14 @@ int subprocess_handshake(struct subprocess_entry *entry, int subprocess_read_status(int fd, struct strbuf *status); +/* + * Like subprocess_read_status(), but a malformed status section fails + * instead of dying: a truncated or malformed packet, and an empty + * packet where a status line or the terminating flush belongs, return + * -1 and leave the stream unusable. subprocess_read_status() cannot + * tell an empty packet from the flush that ends the section, and dies + * on a framing error inside packet_read_line_gently(). + */ +int subprocess_read_status_gently(int fd, struct strbuf *status); + #endif