* fgets() doesn't call fsync() before getting input @ 2019-02-21 15:09 James Larrowe 2019-02-21 15:22 ` Rich Felker 0 siblings, 1 reply; 9+ messages in thread From: James Larrowe @ 2019-02-21 15:09 UTC (permalink / raw) To: musl [-- Attachment #1.1: Type: text/plain, Size: 265 bytes --] I'm writing a program that prints a dialogue to the screen and then asks for input. In musl, the dialogue does not show before fgets() is called, however in glibc it does. That causes a blank prompt and also some confusion. Attached is a minimal example and a log. [-- Attachment #1.2: Type: text/html, Size: 291 bytes --] [-- Attachment #2: minimal-example.c --] [-- Type: application/octet-stream, Size: 164 bytes --] #include <stdio.h> int main() { char buf[9]; fputs("Enter a seven letter word: ", stdout); fgets(buf, 9, stdin); printf("Your word is %s", buf); return 0; } [-- Attachment #3: log --] [-- Type: application/octet-stream, Size: 310 bytes --] chronos@localhost ~/Downloads $ gcc minimal-example.c chronos@localhost ~/Downloads $ ./a.out Enter a seven letter word: letters Your word is letters chronos@localhost ~/Downloads $ musl-gcc minimal-example.c chronos@localhost ~/Downloads $ ./a.out letters Enter a seven letter word: Your word is letters ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fgets() doesn't call fsync() before getting input 2019-02-21 15:09 fgets() doesn't call fsync() before getting input James Larrowe @ 2019-02-21 15:22 ` Rich Felker 2019-02-21 16:31 ` A. Wilcox 0 siblings, 1 reply; 9+ messages in thread From: Rich Felker @ 2019-02-21 15:22 UTC (permalink / raw) To: musl On Thu, Feb 21, 2019 at 10:09:03AM -0500, James Larrowe wrote: > I'm writing a program that prints a dialogue to the screen and then asks > for input. In musl, the dialogue does not show before fgets() is called, > however in glibc it does. That causes a blank prompt and also some > confusion. Attached is a minimal example and a log. This difference is intentional. The specification allows but does not require that attempting to read from a line-buffered input stream causes all line-buffered output streams to be flushed. This behavior was somewhat convenient for old-style input-prompt idioms, but it doesn't scale with large numbers of files open and deadlocks with some multi-threaded usage. The portable solution here for applications is to fflush (not fsync) the particular stream you want flushed. Rich ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fgets() doesn't call fsync() before getting input 2019-02-21 15:22 ` Rich Felker @ 2019-02-21 16:31 ` A. Wilcox 2019-02-21 17:07 ` Rich Felker 0 siblings, 1 reply; 9+ messages in thread From: A. Wilcox @ 2019-02-21 16:31 UTC (permalink / raw) To: musl [-- Attachment #1.1: Type: text/plain, Size: 1252 bytes --] On 02/21/19 09:22, Rich Felker wrote: > On Thu, Feb 21, 2019 at 10:09:03AM -0500, James Larrowe wrote: >> I'm writing a program that prints a dialogue to the screen and then asks >> for input. In musl, the dialogue does not show before fgets() is called, >> however in glibc it does. That causes a blank prompt and also some >> confusion. Attached is a minimal example and a log. > > This difference is intentional. The specification allows but does not > require that attempting to read from a line-buffered input stream > causes all line-buffered output streams to be flushed. This behavior > was somewhat convenient for old-style input-prompt idioms, but it > doesn't scale with large numbers of files open and deadlocks with some > multi-threaded usage. The portable solution here for applications is > to fflush (not fsync) the particular stream you want flushed. > > Rich FWIW, the only package we've come across where this is a problem is mac-fdisk (which hasn't been updated since 1997 - yes, 22 years ago). We have a patch: https://code.foxkit.us/adelie/packages/blob/master/user/mac-fdisk/flush-stdout.patch Best, --arw -- A. Wilcox (awilfox) Project Lead, Adélie Linux https://www.adelielinux.org [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fgets() doesn't call fsync() before getting input 2019-02-21 16:31 ` A. Wilcox @ 2019-02-21 17:07 ` Rich Felker 2019-02-21 19:24 ` Laurent Bercot 2019-02-21 20:16 ` James Larrowe 0 siblings, 2 replies; 9+ messages in thread From: Rich Felker @ 2019-02-21 17:07 UTC (permalink / raw) To: musl On Thu, Feb 21, 2019 at 10:31:36AM -0600, A. Wilcox wrote: > On 02/21/19 09:22, Rich Felker wrote: > > On Thu, Feb 21, 2019 at 10:09:03AM -0500, James Larrowe wrote: > >> I'm writing a program that prints a dialogue to the screen and then asks > >> for input. In musl, the dialogue does not show before fgets() is called, > >> however in glibc it does. That causes a blank prompt and also some > >> confusion. Attached is a minimal example and a log. > > > > This difference is intentional. The specification allows but does not > > require that attempting to read from a line-buffered input stream > > causes all line-buffered output streams to be flushed. This behavior > > was somewhat convenient for old-style input-prompt idioms, but it > > doesn't scale with large numbers of files open and deadlocks with some > > multi-threaded usage. The portable solution here for applications is > > to fflush (not fsync) the particular stream you want flushed. > > > > Rich > > > FWIW, the only package we've come across where this is a problem is > mac-fdisk (which hasn't been updated since 1997 - yes, 22 years ago). > > We have a patch: > > https://code.foxkit.us/adelie/packages/blob/master/user/mac-fdisk/flush-stdout.patch I think it's more of an issue for the early examples in C books and tutorials, which invariably but inexplicably use a 1970s-era "prompt for input" model rather than argv[] or something that would be a lot more familiar (and amenable to testing) to modern readers. Rich ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fgets() doesn't call fsync() before getting input 2019-02-21 17:07 ` Rich Felker @ 2019-02-21 19:24 ` Laurent Bercot 2019-02-21 20:16 ` James Larrowe 1 sibling, 0 replies; 9+ messages in thread From: Laurent Bercot @ 2019-02-21 19:24 UTC (permalink / raw) To: musl >I think it's more of an issue for the early examples in C books and >tutorials, which invariably but inexplicably use a 1970s-era "prompt >for input" model rather than argv[] or something that would be a lot >more familiar (and amenable to testing) to modern readers. Early examples in C books and tutorials, and also in every academic C course ever. I was taught C 25 years ago with the "prompt for input" model; later, I gave advanced C classes to students who were taught the "prompt for input" model 2 years before; and nowadays every newbie C programming question that pops up in forums invariably comes with the very same thing. C courses focusing on good practices are long, long overdue. -_- -- Laurent ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fgets() doesn't call fsync() before getting input 2019-02-21 17:07 ` Rich Felker 2019-02-21 19:24 ` Laurent Bercot @ 2019-02-21 20:16 ` James Larrowe 2019-02-21 20:44 ` Rich Felker 2019-02-22 5:04 ` Markus Wichmann 1 sibling, 2 replies; 9+ messages in thread From: James Larrowe @ 2019-02-21 20:16 UTC (permalink / raw) To: musl [-- Attachment #1: Type: text/plain, Size: 1874 bytes --] Sorry, this was a typo. I meant fflush(). However, it's still not called. It's fixed in my program now, however I'm not sure what to do in this case. Do I just call ffush() on stdin, stdout, and stderr or do I send a patch to fgets()? On Thu, Feb 21, 2019 at 12:08 PM Rich Felker <dalias@libc.org> wrote: > On Thu, Feb 21, 2019 at 10:31:36AM -0600, A. Wilcox wrote: > > On 02/21/19 09:22, Rich Felker wrote: > > > On Thu, Feb 21, 2019 at 10:09:03AM -0500, James Larrowe wrote: > > >> I'm writing a program that prints a dialogue to the screen and then > asks > > >> for input. In musl, the dialogue does not show before fgets() is > called, > > >> however in glibc it does. That causes a blank prompt and also some > > >> confusion. Attached is a minimal example and a log. > > > > > > This difference is intentional. The specification allows but does not > > > require that attempting to read from a line-buffered input stream > > > causes all line-buffered output streams to be flushed. This behavior > > > was somewhat convenient for old-style input-prompt idioms, but it > > > doesn't scale with large numbers of files open and deadlocks with some > > > multi-threaded usage. The portable solution here for applications is > > > to fflush (not fsync) the particular stream you want flushed. > > > > > > Rich > > > > > > FWIW, the only package we've come across where this is a problem is > > mac-fdisk (which hasn't been updated since 1997 - yes, 22 years ago). > > > > We have a patch: > > > > > https://code.foxkit.us/adelie/packages/blob/master/user/mac-fdisk/flush-stdout.patch > > I think it's more of an issue for the early examples in C books and > tutorials, which invariably but inexplicably use a 1970s-era "prompt > for input" model rather than argv[] or something that would be a lot > more familiar (and amenable to testing) to modern readers. > > Rich > [-- Attachment #2: Type: text/html, Size: 2548 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fgets() doesn't call fsync() before getting input 2019-02-21 20:16 ` James Larrowe @ 2019-02-21 20:44 ` Rich Felker 2019-02-22 5:04 ` Markus Wichmann 1 sibling, 0 replies; 9+ messages in thread From: Rich Felker @ 2019-02-21 20:44 UTC (permalink / raw) To: musl On Thu, Feb 21, 2019 at 03:16:23PM -0500, James Larrowe wrote: > Sorry, this was a typo. I meant fflush(). However, it's still not called. > It's fixed in my program now, however I'm not sure what to do in this case. > Do I just call ffush() on stdin, stdout, and stderr or do I send a patch to > fgets()? If you want to ensure the output to stdout actually appears on the terminal/output file before some point in your program, you need to call fflush(stdout) at that point. In your case that would be between the fputs and fgets calls. Rich > On Thu, Feb 21, 2019 at 12:08 PM Rich Felker <dalias@libc.org> wrote: > > > On Thu, Feb 21, 2019 at 10:31:36AM -0600, A. Wilcox wrote: > > > On 02/21/19 09:22, Rich Felker wrote: > > > > On Thu, Feb 21, 2019 at 10:09:03AM -0500, James Larrowe wrote: > > > >> I'm writing a program that prints a dialogue to the screen and then > > asks > > > >> for input. In musl, the dialogue does not show before fgets() is > > called, > > > >> however in glibc it does. That causes a blank prompt and also some > > > >> confusion. Attached is a minimal example and a log. > > > > > > > > This difference is intentional. The specification allows but does not > > > > require that attempting to read from a line-buffered input stream > > > > causes all line-buffered output streams to be flushed. This behavior > > > > was somewhat convenient for old-style input-prompt idioms, but it > > > > doesn't scale with large numbers of files open and deadlocks with some > > > > multi-threaded usage. The portable solution here for applications is > > > > to fflush (not fsync) the particular stream you want flushed. > > > > > > > > Rich > > > > > > > > > FWIW, the only package we've come across where this is a problem is > > > mac-fdisk (which hasn't been updated since 1997 - yes, 22 years ago). > > > > > > We have a patch: > > > > > > > > https://code.foxkit.us/adelie/packages/blob/master/user/mac-fdisk/flush-stdout.patch > > > > I think it's more of an issue for the early examples in C books and > > tutorials, which invariably but inexplicably use a 1970s-era "prompt > > for input" model rather than argv[] or something that would be a lot > > more familiar (and amenable to testing) to modern readers. > > > > Rich > > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fgets() doesn't call fsync() before getting input 2019-02-21 20:16 ` James Larrowe 2019-02-21 20:44 ` Rich Felker @ 2019-02-22 5:04 ` Markus Wichmann 2019-02-25 13:10 ` James Larrowe 1 sibling, 1 reply; 9+ messages in thread From: Markus Wichmann @ 2019-02-22 5:04 UTC (permalink / raw) To: musl On Thu, Feb 21, 2019 at 03:16:23PM -0500, James Larrowe wrote: > Sorry, this was a typo. I meant fflush(). However, it's still not called. > It's fixed in my program now, however I'm not sure what to do in this case. > Do I just call ffush() on stdin, stdout, and stderr or do I send a patch to > fgets()? > You call fflush(stdout). stderr is already unbuffered, so flushing it only makes sense if you used setvbuf() on it beforehand. Why would you, though? Being unbuffered is sort of the defining feature of stderr. Also fflush(stdin) is undefined behavior. fflush() is only defined for output streams. Since you are asking beginner's questions, you are likely to come accross the following idiom in C tutorials: cnt = scanf("Some format", some variables); fflush(stdin); Or maybe the other way round. The reason for this is that scanf() terminates at the newline character at the end of the line you inserted, but doesn't consume it. So the next scanf() will read it as the first thing. The format will likely not allow for whitespace at the start of input, and so the scanf() will fail. The solution is to either allow for the newline by starting the scanf format with a space, or to use: char buf[some appropriate line length]; if (fgets(buf, sizeof buf, stdin)) cnt = sscanf(buf, "Some format", some variables); Ciao, Markus ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fgets() doesn't call fsync() before getting input 2019-02-22 5:04 ` Markus Wichmann @ 2019-02-25 13:10 ` James Larrowe 0 siblings, 0 replies; 9+ messages in thread From: James Larrowe @ 2019-02-25 13:10 UTC (permalink / raw) To: musl [-- Attachment #1: Type: text/plain, Size: 1523 bytes --] Got it. Thank you. On Fri, Feb 22, 2019 at 12:05 AM Markus Wichmann <nullplan@gmx.net> wrote: > On Thu, Feb 21, 2019 at 03:16:23PM -0500, James Larrowe wrote: > > Sorry, this was a typo. I meant fflush(). However, it's still not called. > > It's fixed in my program now, however I'm not sure what to do in this > case. > > Do I just call ffush() on stdin, stdout, and stderr or do I send a patch > to > > fgets()? > > > > You call fflush(stdout). stderr is already unbuffered, so flushing it > only makes sense if you used setvbuf() on it beforehand. Why would you, > though? Being unbuffered is sort of the defining feature of stderr. > > Also fflush(stdin) is undefined behavior. fflush() is only defined for > output streams. Since you are asking beginner's questions, you are > likely to come accross the following idiom in C tutorials: > > cnt = scanf("Some format", some variables); > fflush(stdin); > > Or maybe the other way round. The reason for this is that scanf() > terminates at the newline character at the end of the line you inserted, > but doesn't consume it. So the next scanf() will read it as the first > thing. The format will likely not allow for whitespace at the start of > input, and so the scanf() will fail. > > The solution is to either allow for the newline by starting the scanf > format with a space, or to use: > > char buf[some appropriate line length]; > if (fgets(buf, sizeof buf, stdin)) > cnt = sscanf(buf, "Some format", some variables); > > Ciao, > Markus > [-- Attachment #2: Type: text/html, Size: 1967 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2019-02-25 13:10 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-02-21 15:09 fgets() doesn't call fsync() before getting input James Larrowe 2019-02-21 15:22 ` Rich Felker 2019-02-21 16:31 ` A. Wilcox 2019-02-21 17:07 ` Rich Felker 2019-02-21 19:24 ` Laurent Bercot 2019-02-21 20:16 ` James Larrowe 2019-02-21 20:44 ` Rich Felker 2019-02-22 5:04 ` Markus Wichmann 2019-02-25 13:10 ` James Larrowe
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/musl/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).