mailing list of musl libc
 help / color / mirror / code / Atom feed
* [musl] Possible bug with fputs and fgets mix
@ 2024-08-23  3:55 Ryan Rhee
  2024-08-23 14:24 ` Rich Felker
  0 siblings, 1 reply; 3+ messages in thread
From: Ryan Rhee @ 2024-08-23  3:55 UTC (permalink / raw)
  To: musl

Hello,

I'm running into a problem when calling fputs on stdout before fgets on stdin 
results in the program calling the read syscall before the write syscall.

Example code:

	#include <stdio.h>
	int main() {
		fputs("Enter in something: ", stdout);

		char buf[32];
		fgets(buf, sizeof buf, stdin);

		return 0;
	}

When built with musl-gcc[1] and run, it appears to first poll stdin before writing
to stdout. For example, when built with musl and ran with strace, the following
happens:

	$ strace ./test
	execve("./test", ["./test"], 0x7ffcb2b5a5d0 /* 59 vars */) = 0
	arch_prctl(ARCH_SET_FS, 0x405b78)       = 0
	set_tid_address(0x405cb0)               = 7306
	read(0, hello
	"hello\n", 1024)                = 6
	ioctl(1, TIOCGWINSZ, {ws_row=38, ws_col=110, ws_xpixel=1210, ws_ypixel=1026}) = 0
	writev(1, [{iov_base="Enter in something: ", iov_len=20}, {iov_base=NULL, iov_len=0}], 2Enter in something: ) = 20
	exit_group(0)                           = ?
	+++ exited with 0 +++
	$

As you can see, the read happens before the writev for some reason.

When an fflush(stdout) is placed after the fputs, the output appears before the
input as expected. When the fputs call is replaced with a puts call, the
program works as expected (yet this is not viable, as puts includes a newline
after the string is printed, which is undesired).

Is this a bug with musl, or is a fflush required with fputs unlike with puts?

I am not subscribed to the mailing list, so please CC me with any replies.

Thanks in advance!

[1] Exact command: musl-gcc -std=c11 -o test test.c -static
    musl package version: 1.2.5-2
    Distro: Arch Linux
    gcc version: 14.2.1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [musl] Possible bug with fputs and fgets mix
  2024-08-23  3:55 [musl] Possible bug with fputs and fgets mix Ryan Rhee
@ 2024-08-23 14:24 ` Rich Felker
  2024-08-24  3:52   ` Ryan Rhee
  0 siblings, 1 reply; 3+ messages in thread
From: Rich Felker @ 2024-08-23 14:24 UTC (permalink / raw)
  To: Ryan Rhee; +Cc: musl

On Thu, Aug 22, 2024 at 08:55:01PM -0700, Ryan Rhee wrote:
> Hello,
> 
> I'm running into a problem when calling fputs on stdout before fgets on stdin 
> results in the program calling the read syscall before the write syscall.
> 
> Example code:
> 
> 	#include <stdio.h>
> 	int main() {
> 		fputs("Enter in something: ", stdout);
> 
> 		char buf[32];
> 		fgets(buf, sizeof buf, stdin);
> 
> 		return 0;
> 	}
> 
> When built with musl-gcc[1] and run, it appears to first poll stdin before writing
> to stdout. For example, when built with musl and ran with strace, the following
> happens:
> 
> 	$ strace ./test
> 	execve("./test", ["./test"], 0x7ffcb2b5a5d0 /* 59 vars */) = 0
> 	arch_prctl(ARCH_SET_FS, 0x405b78)       = 0
> 	set_tid_address(0x405cb0)               = 7306
> 	read(0, hello
> 	"hello\n", 1024)                = 6
> 	ioctl(1, TIOCGWINSZ, {ws_row=38, ws_col=110, ws_xpixel=1210, ws_ypixel=1026}) = 0
> 	writev(1, [{iov_base="Enter in something: ", iov_len=20}, {iov_base=NULL, iov_len=0}], 2Enter in something: ) = 20
> 	exit_group(0)                           = ?
> 	+++ exited with 0 +++
> 	$
> 
> As you can see, the read happens before the writev for some reason.
> 
> When an fflush(stdout) is placed after the fputs, the output appears before the
> input as expected. When the fputs call is replaced with a puts call, the
> program works as expected (yet this is not viable, as puts includes a newline
> after the string is printed, which is undesired).
> 
> Is this a bug with musl, or is a fflush required with fputs unlike with puts?
> 
> I am not subscribed to the mailing list, so please CC me with any replies.

This is entirely expected; the fflush is needed.

The C languages allows, but does not require implementations, to have
a read attempt from an interactive line-buffered device auto-flush all
line-buffered output streams before performing the input. But taking
advantage of this allowance is a really, *really* bad idea in a modern
setting. Not only does it have a large performance cost if lots of
streams are open; it also, in any multi-threaded program, would
require obtaining a lock on each open output stream one-by-one every
time you perform a line-buffered input operation, to ensure that none
of them are line-buffered output with pending unwritten data. Under
any complex usage pattern, this almost surely leads to *deadlock*
scenarios, where lack of forward progress on the input operation
(because it's waiting to check output streams) causes an output
operation to block forever with its lock held. (Think of setups where
some of these streams are pipes or network sockets.)

As such, musl does not use the allowance to do this, and never
implicitly flushes output streams. Portable programs need to be
prepared for this, and explicitly flush whatever output stream(s) they
want flushed before doing input with a prompt like this.

(Note that if the prompt ended in a newline, though, just being
line-buffered would have ensured it got flushed. Explicit flushing is
only needed when it doesn't end in a newline or if you're using a
fully-buffered rather than line-buffered output stream.)

Rich

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [musl] Possible bug with fputs and fgets mix
  2024-08-23 14:24 ` Rich Felker
@ 2024-08-24  3:52   ` Ryan Rhee
  0 siblings, 0 replies; 3+ messages in thread
From: Ryan Rhee @ 2024-08-24  3:52 UTC (permalink / raw)
  To: Rich Felker; +Cc: musl

On Fri Aug 23, 2024 at 7:24 AM PDT, Rich Felker wrote:
> This is entirely expected; the fflush is needed.
>
> The C languages allows, but does not require implementations, to have
> a read attempt from an interactive line-buffered device auto-flush all
> line-buffered output streams before performing the input.

[snip]

> As such, musl does not use the allowance to do this, and never
> implicitly flushes output streams. Portable programs need to be
> prepared for this, and explicitly flush whatever output stream(s) they
> want flushed before doing input with a prompt like this.
>
> (Note that if the prompt ended in a newline, though, just being
> line-buffered would have ensured it got flushed. Explicit flushing is
> only needed when it doesn't end in a newline or if you're using a
> fully-buffered rather than line-buffered output stream.)
>
> Rich

Oh, alright, that's good information to know for the future.

Thanks for all this information, and thanks for all the work on the library.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-08-24 14:23 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-08-23  3:55 [musl] Possible bug with fputs and fgets mix Ryan Rhee
2024-08-23 14:24 ` Rich Felker
2024-08-24  3:52   ` Ryan Rhee

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).