bug-gawk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Undetected fatal errors from redirected print


From: Miguel Pineiro Jr.
Subject: Undetected fatal errors from redirected print
Date: Mon, 22 Nov 2021 20:56:30 -0500
User-agent: Cyrus-JMAP/3.5.0-alpha0-1371-g2296cc3491-fm-20211109.003-g2296cc34

While surveying the io error handling of a few awks, I found that gawk 
sometimes reports success upon a fatal failure to write a redirected print (or 
printf) statement's data.

Fedora 35 Worstation
Linux 5.14.17-301.fc35.x86_64
GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0-p13, GNU MP 6.2.0)
GNU Awk, commit a08cc63b, 2021-09-09, the final version in master using 
Autoconf 2.69.

I tested those two versions. I'm assuming the issue still exists in master, but 
I did not confirm it. I did take a peek at `git diff a08cc63b..master 
interpret.h builtin.c io.c` and none of the few changes appear to be a remedy 
for the misbehavior I'm seeing.

My test script (which is at the end of this mail) tests the following commands:

gawk 'BEGIN {print "42" > "answer.txt"}'
gawk 'BEGIN {print "42" > "answer.txt"; close("answer.txt")}'
gawk 'BEGIN {print "42"}' > answer.txt

It uses strace to intercept and sabotage attempts to write the number 42 into 
answer.txt. If all were well, gawk would emit an error message and return a 
non-zero exit status.

The first two commands have a redirected print statement. The first command 
leaves the closing of the stream to gawk. The second, closes the stream 
explicitly. In both cases, gawk fails to detect fatal io errors and returns 
success.

GAWK CMD: gawk 'BEGIN {print "42" > "answer.txt"}'
GAWK RET: 0
BYTES WRITTEN: 0
SYSCALL TRACE:  write(3, "42\n", 3)              = -1 ENOSYS (Function not 
implemented) (INJECTED)

GAWK CMD: gawk 'BEGIN {print "42" > "answer.txt"; close("answer.txt")}'
GAWK RET: 0
BYTES WRITTEN: 0
SYSCALL TRACE:  write(3, "42\n", 3)              = -1 ENOSYS (Function not 
implemented) (INJECTED)

I didn't debug, but I did look at the code for a bit. I think the problem is in 
close_rp. When it calls fclose/pclose on a redirected output stream with 
pending data in its buffer, it fails to discriminate between a fatal write(2) 
error during the flush and a subsequent, non-fatal close(2) error when freeing 
the underlying file descriptor. The fatal write errors then slip through as 
benign close errors.

Un-redirected output is not affected. On its way out, in close_io, gawk flushes 
stdout and stderr. If either flush fails, the failure is detected, a warning 
produced, and a non-zero status returned. All good. 

GAWK CMD: gawk 'BEGIN {print "42"}' > answer.txt
gawk: warning: error writing standard output: Function not implemented
GAWK RET: 1
BYTES WRITTEN: 0
SYSCALL TRACE:  write(1, "42\n", 3)              = -1 ENOSYS (Function not 
implemented) (INJECTED)

In case it's of use to anyone, my script follows. It requires strace and it 
will create two files in the working directory, answer.txt and trace.txt.

Take care,
Miguel


# Commands to be tested served on stdin
exec <<'EOF'
gawk 'BEGIN {print "42" > "answer.txt"}'
gawk 'BEGIN {print "42" > "answer.txt"; close("answer.txt")}'
gawk 'BEGIN {print "42"}' > answer.txt
EOF

# Sabotage gawk's attempt to write "42" to answer.txt.
while IFS= read -r gcmd; do
        echo
        >answer.txt >trace.txt
        echo GAWK CMD: "$gcmd"
        strace -fo trace.txt -P answer.txt -e fault=write sh -c "$gcmd"
        echo GAWK RET: $?
        echo BYTES WRITTEN: $(wc -c < answer.txt)
        echo SYSCALL TRACE: "$(sed -n '/write/s/^[^ ]*//p' trace.txt)"
done



reply via email to

[Prev in Thread] Current Thread [Next in Thread]