Subject: bug#74159: Unexpected exit code of 0 when -q is set and close_stdout fails

From: Jan Černohorský <[email-masked]>
Date: Fri, 1 Nov 2024 14:10:43 +0100

Hello,

I've encountered a particularly interesting bug in GNU grep yesterday while 
hunting some issues with LibreOffice (if you're interested in the whole 
post-mortem, it can be read here: 
https://grsc.cz/blog/loffice-linux-issues/, but it's mostly not relevant 
for this bug).

Whenever the `-q` option is used, grep can exit with a 0, even if no 
match has been found and an error has been encountered. In particular, 
when the `close_stdout` function is called and the `close` syscall 
fails, grep exits with 0, even when it's not supposed to.

While reading the source code, I found out that when the `-q` option is 
detected (grep.c:2697), the `exit_failure` variable is set to 0. This 
causes any error, when not specially handled, to exit with 0, even 
before any match is found. This is also true for the `close_stdout` libc 
function, which hard exits using `_exit(exit_failure)` when the syscall 
fails.

This, at first glance, (and pardon me if I'm wrong, I haven't looked 
into the source code that deeply) seems to me as bad design, since it 
makes the code prone to multiple such mistakes – where someone 
inadvertently uses the `exit_failure` variable without realising it 
makes the program return the wrong code. It would make much more sense 
to me (and again, I don't know whether this is possible) to set the 
`exit_failure` variable to 0 only *after* the first match is found, 
preventing such issues altogether. It also makes more sense semantically 
IMO, as the `-q` option states that errors are ignored only when a match 
is found, not always.

As I feel this is more of a design decision than a straightforward fix, 
I'm not sending a patch, but I'll be glad to assist any efforts to 
fix this.

CC'd are my colleagues who helped discover the issue.

Regards,
Jan