mailing list of musl libc
 help / color / mirror / code / Atom feed
* 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).