Bug 3746 - exit violates POSIX on seekable stdin
Summary: exit violates POSIX on seekable stdin
Status: RESOLVED INVALID
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.3.4
: P2 normal
Target Milestone: ---
Assignee: Ulrich Drepper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-12-16 20:09 UTC by Eric Blake
Modified: 2014-07-17 14:54 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Blake 2006-12-16 20:09:36 UTC
POSIX requires in XCU 1.11:

"When a standard utility reads a seekable input file and terminates without an
error before it reaches end-of-file, the utility shall ensure that the file
offset in the open file description is properly positioned just past the last
byte processed by the utility....

    tail -n +2 file
    (sed -n 1q; cat) < file
    cat file | (sed -n 1q; cat)

The second command is equivalent to the first only when the file is seekable."
http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap01.html

POSIX also requires that "All of the file descriptors, directory streams, [XSI]
[Option Start]  conversion descriptors, and message catalog descriptors [Option
End]  open in the calling process shall be closed" on exit.
http://www.opengroup.org/onlinepubs/009695399/functions/exit.html

Both of these conditions are violated with glibc:

$ echo 1 2 3 | tr ' ' '\n' > file
$ (sed -n 1q; cat) < file
$ strace sed -ne 1q < file 2>&1 |tail
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0xb7dd2000
read(0, "1\n2\n3\n", 4096)              = 6
open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=21544, ...}) = 0
mmap2(NULL, 21544, PROT_READ, MAP_SHARED, 3, 0) = 0xb7dcc000
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
Process 21067 detached

Oops - the process failed to lseek back to offset 2, which is the next byte not
processed by sed; and failed to call close(0).

A utility that is worried about POSIX compliance can use the workaround of
manually calling fflush(stdin), fseek(stdin, 0, SEEK_CUR), fclose(stdin) prior
to exit(), but this should be taken care of by libc, as is the case on other
platforms such as Solaris.
Comment 1 Ulrich Drepper 2006-12-16 20:29:27 UTC
The seek is an XCU requirement, it is the programs problem.  There is no such
requirement on the runtime.  Don't try to push your problems off to somebody else.

And file descriptors are implicitly closed when a process terminates.  Closing
them in exit means some programs stop working.
Comment 2 Eric Blake 2006-12-18 18:26:13 UTC
No, this is an XSH requirement.  Quoting from
http://www.opengroup.org/onlinepubs/009695399/functions/exit.html,

"The exit() function shall then flush all open streams with unwritten buffered 
data, close all open streams, and remove all files created by tmpfile()."

In other words, glibc is at fault for not closing stdin after all atexit 
handlers have completed.
Comment 3 Eric Blake 2006-12-18 18:57:10 UTC
Furthermore, Austin Group interpretations 002 and 085 will tighten the wording 
in this area of the next revision of POSIX, making it clear that it is the 
library's job as part of exit() to close read streams, and that when closing 
such a stream that is visiting a seekable file description, the file 
description's offset must be adjusted correctly.

http://www.opengroup.org/austin/interps/uploads/40/6806/AI-002.txt
http://www.opengroup.org/austin/interps/uploads/40/9984/AI-085.txt
Comment 4 Ulrich Drepper 2006-12-18 19:14:16 UTC
It will never happen.  What is so hard to understand in "Closing
them in exit means some programs stop working."?
Comment 5 Eric Blake 2006-12-18 20:38:01 UTC
Please give me an example of a program that would be broken if actions 
equivalent to fclose(stdin) were implicitly performed in exit() after all atexit
() handlers have completed as POSIX currently requires, and that cannot be 
fixed by recompiling that program to use _exit() instead.  With such a program 
identified, I would be glad to use that example to help persuade the Austin 
group to reword the requirements in such a way that the current glibc behavior 
would be compliant, where it currently is not.  If you can't do that, then I 
can't see why you keep closing this report as invalid, since it really IS a 
POSIX compliance bug, whether you plan on fixing it or not.