The following bug was reported for tee(1) of latest 9.11 version on openSUSE:

  https://bugzilla.suse.com/show_bug.cgi?id=1265378

The reproducer is about tee(1) reading from a pipe from the 'scriptreplay' tool.
The input for 'scriptreplay' is attached to the ticket, but as it is 38K, I 
thought
it is still small enough to share here.

How to reproduce:
  $ tar xf $ATTACHMENT
  $ scriptreplay -d 6 typescript.timing typescript | timeout 25 tee .test

At the end of the 'screenreplay' recording, tee(1) goes into a 100% busy loop
until it gets killed by timeout(1).

  read(0, "bernhard@node52:~/osc/t/openSUSE"..., 8192) = 51
  write(3, "bernhard@node52:~/osc/t/openSUSE"..., 51) = 51
  read(0, "exit\r\n\n", 8192) = 7
  write(3, "exit\r\n\n", 7) = 7
  read(0, "", 8192)       = 0
  poll([{fd=-1}, {fd=3, events=POLLOUT}], 2, -1) = 1 ([{fd=3, revents=POLLOUT}])
  poll([{fd=-1}, {fd=3, events=POLLOUT}], 2, -1) = 1 ([{fd=3, revents=POLLOUT}])
  poll([{fd=-1}, {fd=3, events=POLLOUT}], 2, -1) = 1 ([{fd=3, revents=POLLOUT}])
  poll([{fd=-1}, {fd=3, events=POLLOUT}], 2, -1) = 1 ([{fd=3, revents=POLLOUT}])

The OP claims he bisected the problem to this commit:

  9b855166e tee: prefer file descriptors over streams

GDB shows that tee(1) does not ever get out of the endless loop in close_wait():

  #0  0x00007fa801497f9a in __internal_syscall_cancel () from /lib64/libc.so.6
  #1  0x00007fa801497fc1 in __syscall_cancel () from /lib64/libc.so.6
  #2  0x00007fa8015128ea in poll () from /lib64/libc.so.6
  #3  0x00000000004035df in poll (__fds=0x7fffceca2c70, __nfds=2, 
__timeout=<optimized out>) \
        at /usr/include/bits/poll2.h:44
  #4  iopoll_internal (fdin=fdin@entry=-1, fdout=fdout@entry=3, 
block=block@entry=true, \
                       broken_output=broken_output@entry=false) \
        at src/iopoll.c:82
  #5  0x0000000000403713 in wait_for_nonblocking_write (fd=<optimized out>) \
        at src/iopoll.c:187
  #6  close_wait (fd=3) \
        at src/iopoll.c:202
  #7  0x0000000000402cdb in tee_files (nfiles=1, files=<optimized out>, 
pipe_check=false) \
        at src/tee.c:332
  #8  0x00000000004028c4 in main (argc=2, argv=0x7fffceca4e68) \
        at src/tee.c:184

Note 1: for me, the issue is not reproducible every time, but I saw it as least
1 out of 20 times.

Note 2: if the effect happens, then the terminal does not show the end of the 
screenreplay.
strace shows that tee(1) is getting EAGAIN, and from then on stops outputting 
to stdout,
and only continues to write to FD 3.

  read(0, "[   26s] AutoGen: Parsing \"SRC:/"..., 8192) = 8192
  write(1, "[   26s] AutoGen: Parsing \"SRC:/"..., 8192) = 8192
  write(3, "[   26s] AutoGen: Parsing \"SRC:/"..., 8192) = 8192
  read(0, "de/qt6/QtDBus -I/usr/include/KF6"..., 8192) = 8192
  write(1, "de/qt6/QtDBus -I/usr/include/KF6"..., 8192) = 1661
  fcntl(1, F_GETFL)       = 0x8802 (flags O_RDWR|O_NONBLOCK|O_LARGEFILE)
  write(2, "tee: ", 5)    = -1 EAGAIN (Resource temporarily unavailable)
  write(2, "'standard output'", 17) = -1 EAGAIN (Resource temporarily 
unavailable)
  write(2, "\n", 1)       = -1 EAGAIN (Resource temporarily unavailable)
  write(3, "de/qt6/QtDBus -I/usr/include/KF6"..., 8192) = 8192
  read(0, "p\", because it doesn't exist, fr"..., 8192) = 8192
  write(3, "p\", because it doesn't exist, fr"..., 8192) = 8192
  read(0, "L_CAST_FROM_STRING -DQT_OPENGL_L"..., 8192) = 8192
  write(3, "L_CAST_FROM_STRING -DQT_OPENGL_L"..., 8192) = 8192

Note 3: Regardless whether the tee(1) infloop happens or not, the terminal is 
showing
some debris after terminating tee(1):

  
:1+r6E616D65=787465726D2D323536636F6C6F72^[\^[[8;61;270t^[[61;10R^[[61;270R^[[8;61;270t^[[61;1R^[[61;270R

Note 4:. Interestingly, I also saw another effect in some of the runs:
the regular output on the terminal stopped somewhere in the middle of the 
compilation section
of the screen recording, and tee terminates with
  tee: 'standard output'
and with $? = 130.  Not sure this is the same case.

I'm a bit confused, and I guess we have at least the following issues in the 
code:
- tee should continue to write to stdout on EAGAIN,
- the final close_wait function should not infloop.

Have a nice day,
Berny

Attachment: typescript.tar.gz
Description: application/gzip

Reply via email to