bug-hello
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: hello-2.11 fails multibyte-1 and atexit-1 on musl


From: Sergei Trofimovich
Subject: Re: hello-2.11 fails multibyte-1 and atexit-1 on musl
Date: Sat, 29 Jan 2022 10:18:38 +0000

On Thu, 27 Jan 2022 22:08:57 +0000
Reuben Thomas <rrt@sc3d.org> wrote:

> On Wed, 26 Jan 2022 at 12:59, Sergei Trofimovich <slyich@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

Attachment: 0001-hello-force-stdout-buffering-until-atexit.patch
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]