On Thu, 27 Jan 2022 22:08:57 +0000 Reuben Thomas <r...@sc3d.org> wrote:
> On Wed, 26 Jan 2022 at 12:59, Sergei Trofimovich <sly...@gmail.com> wrote: > > > > Thanks for the report! > > > From what I understand at > > > > https://wiki.musl-libc.org/functional-differences-from-glibc.html#Character-sets-and-locale > > musl deliberately supports any char -> wchar_t (and back) conversion for > > any char in LC_CTYPE=C. And thus the multibyte-1 test will always fail > > there. > > I also found this problem on macOS. I tried on my GNU/Linux system > using an ISO-8859 locale for the test, but the multibyte conversion > does not fail! (e.g. in en_GB.iso88591). I also tried with > ru_RU.KOI8-R, same result. > > It seems then that it's not going to be possible in general to find a > locale that will fail. These results suggest that on some libc's, > conversion will always succeed. > > Hence, I'm removing the test. > > > Not sure why atexit-1 fails. It seems to rely on > > close_stdout_set_file_name() call in atexit(), but I don't see where in > > code it's registered to call. > > Line 155 registers close_stdout. I can't see anything wrong with the > way this is done; I'd be very grateful if you could investigate > further. Aha, I misinterpreted the atexit handler and did not notice close_stdout_set_file_name() is part of gnulib. Attached possible patch. Passes atexit-1 test on musl and glibc. Some details: The real reason to failure on musl is stream status and errno value status in close_stream(). If I add a bit of fprintf() debugging it becomes clearer: void close_stdout (void) { fprintf(stderr, "%s: errno=%d\n", __func__, errno); if (close_stream (stdout) != 0 && !(ignore_EPIPE && errno == EPIPE)) { fprintf(stderr, "%s: after close_stream() errno=%d\n", __func__, errno); ... Execution on glibc: close_stdout: errno=0 close_stdout: after close_stream() errno=28 ./hello: write error: No space left on device Execution on glibc: close_stdout: errno=28 close_stdout: after close_stream() errno=0 hello: write error On glibc stdout flush did not happen yet by the time we get to atexit(). ltrace also gives the same hint: On glibc: $ ltrace ./hello ... strlen("Hello, world!") = 13 malloc(56) = 0x10c78c0 mbsrtowcs(0x10c78c0, 0x7ffeb2b630a0, 14, 0x7ffeb2b630a8) = 13 wprintf(0x408298, 0x10c78c0, 177, 0) = 14 free(0x10c78c0) = <void> exit(0 <unfinished ...> __errno_location() = 0x7fa894ceb548 fprintf(0x7fa894cdf440, "%s: errno=%d\n", "close_stdout", 0close_stdout: errno=0 ) = 22 __fpending(0x7fa894cdf520, 0x7ffeb2b609d0, 0, 0x7fa894c11343) = 14 ferror(0x7fa894cdf520) = 0 fclose(0x7fa894cdf520) = -1 fprintf(0x7fa894cdf440, "%s: after close_stream() errno=%"..., "close_stdout", 28close_stdout: after close_stream() errno=28 ) = 44 dcgettext(0, 0x40836e, 5, 0x7fa894c11343) = 0x40836e error(0, 28, 0x4080c8, 0x40836e./hello: write error: No space left on device ) = 0 _exit(1 <no return ...> +++ exited (status 1) +++ Note that wprintf() queued 14 symbols successfully. On musl queueing did not happen and thus stream close did not return error: $ ltrace ./hello ... strlen("Hello, world!") = 13 malloc(56) = 0x5570a96ddb10 mbsrtowcs(0x5570a96ddb10, 0x7ffdcb755398, 14, 0x7ffdcb7553a0) = 13 wprintf(0x5570a96d9298, 0x5570a96ddb10, 0xffffff3e, 1) = 0xffffffff free(0x5570a96ddb10) = <void> exit(0 <unfinished ...> __errno_location() = 0x7fad63ed0b1c fprintf(0x7fad63ece0c0, "%s: errno=%d\n", "close_stdout", 28close_stdout: errno=28 ) = 23 __fpending(0x7fad63ece2c0, 0x7ffdcb755040, 0xffffffff, 0) = 0 ferror(0x7fad63ece2c0) = 1 fclose(0x7fad63ece2c0) = 0 __errno_location() = 0x7fad63ed0b1c fprintf(0x7fad63ece0c0, "%s: after close_stream() errno=%"..., "close_stdout", 0close_stdout: after close_stream() errno=0 ) = 43 gettext(0x5570a96d92ba, 0x7ffdcb755040, 0xffffffff, 0) = 0x5570a96d92ba fileno(0x7fad63ece2c0) = 1 fcntl(1, 3, 0x636f6c2f7273752f, 0x5570a96d92ba) = -1 fprintf(0x7fad63ece0c0, "%s: ", "hello"hello: ) = 7 vfprintf(0x7fad63ece0c0, "%s", 0x7ffdcb755230write error) = 11 putc(10, 0x7fad63ece0c0, 0xffffffff, 0 ) = 10 fflush(0x7fad63ece0c0) = 0 _exit(1 <no return ...> +++ exited (status 1) +++ On glibc write() happens in atexit: $ strace ./hello ... newfstatat(1, "", {st_mode=S_IFCHR|0666, st_rdev=makedev(0x1, 0x7), ...}, AT_EMPTY_PATH) = 0 ioctl(1, TCGETS, 0x7ffee70babb0) = -1 ENOTTY (Inappropriate ioctl for device) write(2, "close_stdout: errno=0\n", 22close_stdout: errno=0 ) = 22 write(1, "Hello, world!\n", 14) = -1 ENOSPC (No space left on device) close(1) = 0 write(2, "close_stdout: after close_stream"..., 44close_stdout: after close_stream() errno=28 ) = 44 write(2, "./hello: ", 9./hello: ) = 9 write(2, "write error", 11write error) = 11 On musl write() happens way before atexit, at main(): $ strace ./hello ... writev(1, [{iov_base="Hello, world!", iov_len=13}, {iov_base="\n", iov_len=1}], 2) = -1 ENOSPC (No space left on device) writev(2, [{iov_base="close_stdout: errno=28\n", iov_len=23}, {iov_base=NULL, iov_len=0}], 2close_stdout: errno=28 ) = 23 close(1) = 0 writev(2, [{iov_base="close_stdout: after close_stream"..., iov_len=43}, {iov_base=NULL, iov_len=0}], 2close_stdout: after close_stream() errno=0 ) = 43 fcntl(1, F_GETFL) = -1 EBADF (Bad file descriptor) writev(2, [{iov_base="hello: ", iov_len=7}, {iov_base=NULL, iov_len=0}], 2hello: ) = 7 writev(2, [{iov_base="write error", iov_len=11}, {iov_base=NULL, iov_len=0}], 2write error) = 11 writev(2, [{iov_base="", iov_len=0}, {iov_base="\n", iov_len=1}], 2 ) = 1 exit_group(1) = ? +++ exited with 1 +++ ... -- Sergei
From d1828b32e00bbd6fe3dee3bdfafb6adf62a9dabc Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich <sly...@gmail.com> Date: Sat, 29 Jan 2022 10:11:19 +0000 Subject: [PATCH] hello: force stdout buffering until atexit() Before the change atexit-1 test failed on musl libc. test assumed that actual I/O to stdout will happen at atexit() call and not before. But musl performed I/O earlier and did not buffer any data. To maintain the assumption of buffered I/O the change enables full buffering for stdout with enough buffer to hold all potential output. * main: set full buffering on stdout. --- src/hello.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hello.c b/src/hello.c index 2e7d38e..715a3bb 100644 --- a/src/hello.c +++ b/src/hello.c @@ -134,6 +134,9 @@ main (int argc, char *argv[]) mbstate_t mbstate = { 0, }; size_t len; + /* Make sure real I/O will not happen until atexit(). */ + setvbuf(stdout, NULL, _IOFBF, 1024); + set_program_name (argv[0]); /* Set locale via LC_ALL. */ -- 2.34.1