Page MenuHomeFreeBSD

getdelim(3): Fix losing data on EAGAIN
ClosedPublic

Authored by bdrewery on Aug 25 2021, 11:18 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sat, Mar 30, 7:22 AM
Unknown Object (File)
Sat, Mar 30, 7:18 AM
Unknown Object (File)
Sat, Mar 30, 7:17 AM
Unknown Object (File)
Mar 1 2024, 7:51 AM
Unknown Object (File)
Feb 16 2024, 4:06 PM
Unknown Object (File)
Feb 6 2024, 8:10 AM
Unknown Object (File)
Feb 3 2024, 7:15 PM
Unknown Object (File)
Jan 9 2024, 6:52 PM
Subscribers

Details

Summary

Currently when an [EAGAIN] is encountered we return a partial result
that does not contain the delimeter. On the next (successful) read we
were returning the next part of the line without the preceding string
from the first failed call.

Fix this by using the same mechanism as ungetc(3) does. For the buffered
case we could simply set fp->_r and fp->_p back to their values before
sappend() is ran but for simplicity ungetc(3) is done in there as well.

This, and a simpler test repro, were posted on an OpenBSD mailing list a few
years ago as well.
http://openbsd-archive.7691.n7.nabble.com/getdelim-and-O-NONBLOCK-td363434.html
http://webcache.googleusercontent.com/search?q=cache:jEH3oOsWpcAJ:openbsd-archive.7691.n7.nabble.com/getdelim-and-O-NONBLOCK-td363434.html+&cd=1&hl=en&ct=clnk&gl=us

Test Plan
# Without fix
getdelim_test:empty_NULL_buffer  ->  passed  [0.003s]
getdelim_test:eof  ->  passed  [0.003s]
getdelim_test:getline_basic  ->  passed  [0.003s]
getdelim_test:invalid_params  ->  passed  [0.003s]
getdelim_test:nonblock_eagain_buffered  ->  failed: /root/git/freebsd/main2/lib/libc/tests/stdio/getdelim_test.c:354: "" != line ( != first line partir)  [0.003s]
getdelim_test:nonblock_eagain_unbuffered  ->  failed: /root/git/freebsd/main2/lib/libc/tests/stdio/getdelim_test.c:354: "" != line ( != first line partir)  [0.003s]
getdelim_test:nul  ->  passed  [0.002s]
getdelim_test:stream_error  ->  passed  [0.002s]

Results file id is usr_tests_lib_libc_stdio.20210825-232552-052032
Results saved to /root/.kyua/store/results.usr_tests_lib_libc_stdio.20210825-232552-052032.db

6/8 passed (2 failed)

# With fix
getdelim_test:empty_NULL_buffer  ->  passed  [0.003s]
getdelim_test:eof  ->  passed  [0.003s]
getdelim_test:getline_basic  ->  passed  [0.003s]
getdelim_test:invalid_params  ->  passed  [0.002s]
getdelim_test:nonblock_eagain_buffered  ->  passed  [0.004s]
getdelim_test:nonblock_eagain_unbuffered  ->  passed  [0.004s]
getdelim_test:nul  ->  passed  [0.002s]
getdelim_test:stream_error  ->  passed  [0.003s]

Results file id is usr_tests_lib_libc_stdio.20210825-231537-629982
Results saved to /root/.kyua/store/results.usr_tests_lib_libc_stdio.20210825-231537-629982.db

8/8 passed (0 failed)

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

  • Make failure of the partner process less prominent in kyua output

I believe stdio is not supposed to work (correctly) with non-blocking file descriptors. I do not object against attempts to make part of it work regardless, but I am not sure it is possible without making it all functional.

lib/libc/stdio/getdelim.c
143–144

You can reduce indent for if (errno == EAGAIN) block if change this line into

if (__sfeof(fp))
   goto done; /* hit EOF */
144

I suspect it is possible for __srefill() to return EOF but not set errno in some situations. So this test might be against previous error.

152

In principle ungetc() can return error AKA EOF.

bdrewery marked 3 inline comments as done.

Address feedback

  • Reset errno before __srefill as it may return EOF without setting it.
  • Destaircase
  • Handle (malloc failing) EOF error from __ungetc
In D31687#714822, @kib wrote:

I believe stdio is not supposed to work (correctly) with non-blocking file descriptors. I do not object against attempts to make part of it work regardless, but I am not sure it is possible without making it all functional.

Thank you. At least for this use I have not had any further trouble. I would not be surprised if more comes up

kib added inline comments.
lib/libc/stdio/getdelim.c
152

I suggest to brace the multi-line body of the loop.

This revision is now accepted and ready to land.Aug 26 2021, 5:28 PM
bdrewery marked an inline comment as done.
  • add braces around ungetc loop
This revision now requires review to proceed.Aug 26 2021, 6:57 PM
This revision was not accepted when it landed; it landed in state Needs Review.Sep 2 2021, 6:27 PM
This revision was automatically updated to reflect the committed changes.