* [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close @ 2013-12-03 18:05 Mark Mentovai 2013-12-04 0:16 ` Ondřej Bílka 0 siblings, 1 reply; 21+ messages in thread From: Mark Mentovai @ 2013-12-03 18:05 UTC (permalink / raw) To: libc-alpha When the close system call is interrupted by a signal, the state of its file descriptor argument is not specified[1]. On Linux, a close that fails with EINTR must not be restarted because the file descriptor is guaranteed to have been closed at that point[2]. Note that the kernel itself never restarts a close when SA_RESTART is set or when no user-space signal handler is present[3]. Because glibc is widely used on Linux, its documentation should state affirmatively that the TEMP_FAILURE_RETRY, which restarts interrupted system calls that fail with EINTR, is not to be used with close on Linux. Examples in glibc documentation should avoid recommending wrapping close with TEMP_FAILURE_RETRY. [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html [2] http://lkml.org/lkml/2005/9/10/129 [3] http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/?id=ee731f4f7880b09ca147008ab46ad4e5f72cb8b 2013-12-03 Mark Mentovai <mark@chromium.org> * manual/llio.texi (Opening and Closing Files): Document that TEMP_FAILURE_RETRY should not be used with close on Linux. (Duplicating Descriptors): Don't wrap close in TEMP_FAILURE_RETRY in example code. --- manual/llio.texi | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/manual/llio.texi b/manual/llio.texi index b6c9260..f04a2cf 100644 --- a/manual/llio.texi +++ b/manual/llio.texi @@ -253,11 +253,9 @@ The @var{filedes} argument is not a valid file descriptor. @item EINTR The @code{close} call was interrupted by a signal. @xref{Interrupted Primitives}. -Here is an example of how to handle @code{EINTR} properly: - -@smallexample -TEMP_FAILURE_RETRY (close (desc)); -@end smallexample +On Linux, @code{close} will have closed its file descriptor argument even when +reporting @code{EINTR}. It is not safe to retry calling @code{close} in this +case, as would be done when wrapped in the @code{TEMP_FAILURE_RETRY} macro. @item ENOSPC @itemx EIO @@ -2765,7 +2763,7 @@ if (pid == 0) @dots{} file = TEMP_FAILURE_RETRY (open (filename, O_RDONLY)); dup2 (file, STDIN_FILENO); - TEMP_FAILURE_RETRY (close (file)); + close (file); execv (program, NULL); @} @end smallexample -- 1.8.3.4 ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2013-12-03 18:05 [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close Mark Mentovai @ 2013-12-04 0:16 ` Ondřej Bílka 2013-12-04 0:38 ` Rich Felker ` (2 more replies) 0 siblings, 3 replies; 21+ messages in thread From: Ondřej Bílka @ 2013-12-04 0:16 UTC (permalink / raw) To: Mark Mentovai; +Cc: libc-alpha On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: > When the close system call is interrupted by a signal, the state of its > file descriptor argument is not specified[1]. On Linux, a close that > fails with EINTR must not be restarted because the file descriptor is > guaranteed to have been closed at that point[2]. Note that the kernel > itself never restarts a close when SA_RESTART is set or when no > user-space signal handler is present[3]. > This is linux problem, POSIX now says http://austingroupbugs.net/view.php?id=529 If close( ) is interrupted by a signal that is to be caught, then it is unspecified whether it returns -1 with errno set to [EINTR] with fildes remaining open, or returns -1 with errno set to [EINPROGRESS] with fildes being closed, or returns 0 to indicate successful completion; except that if POSIX_CLOSE_RESTART is defined as 0, then the option of returning -1 with errno set to [EINTR] and fildes remaining open shall not occur. If close() returns -1 with errno set to [EINTR], it is unspecified whether fildes can subsequently be passed to any function except close( ) or posix_close( ) without error. For all other error situations (except for [EBADF] where fildes was invalid), fildes shall be closed. If fildes was closed even though the close operation is incomplete, the close operation shall continue asynchronously and the process shall have no further ability to track the completion or final status of the close operation. > Because glibc is widely used on Linux, its documentation should state > affirmatively that the TEMP_FAILURE_RETRY, which restarts interrupted > system calls that fail with EINTR, is not to be used with close on > Linux. Examples in glibc documentation should avoid recommending > wrapping close with TEMP_FAILURE_RETRY. > > [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html > [2] http://lkml.org/lkml/2005/9/10/129 > [3] http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/?id=ee731f4f7880b09ca147008ab46ad4e5f72cb8b > > 2013-12-03 Mark Mentovai <mark@chromium.org> > > * manual/llio.texi (Opening and Closing Files): Document that > TEMP_FAILURE_RETRY should not be used with close on Linux. > (Duplicating Descriptors): Don't wrap close in TEMP_FAILURE_RETRY > in example code. > > --- > manual/llio.texi | 10 ++++------ > 1 file changed, 4 insertions(+), 6 deletions(-) > > diff --git a/manual/llio.texi b/manual/llio.texi > index b6c9260..f04a2cf 100644 > --- a/manual/llio.texi > +++ b/manual/llio.texi > @@ -253,11 +253,9 @@ The @var{filedes} argument is not a valid file descriptor. > @item EINTR > The @code{close} call was interrupted by a signal. > @xref{Interrupted Primitives}. > -Here is an example of how to handle @code{EINTR} properly: > - > -@smallexample > -TEMP_FAILURE_RETRY (close (desc)); > -@end smallexample > +On Linux, @code{close} will have closed its file descriptor argument even when > +reporting @code{EINTR}. It is not safe to retry calling @code{close} in this > +case, as would be done when wrapped in the @code{TEMP_FAILURE_RETRY} macro. > > @item ENOSPC > @itemx EIO > @@ -2765,7 +2763,7 @@ if (pid == 0) > @dots{} > file = TEMP_FAILURE_RETRY (open (filename, O_RDONLY)); > dup2 (file, STDIN_FILENO); > - TEMP_FAILURE_RETRY (close (file)); > + close (file); > execv (program, NULL); > @} > @end smallexample > -- > 1.8.3.4 ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2013-12-04 0:16 ` Ondřej Bílka @ 2013-12-04 0:38 ` Rich Felker 2013-12-05 17:35 ` Mark Mentovai 2016-12-05 14:49 ` Michael Kerrisk 2 siblings, 0 replies; 21+ messages in thread From: Rich Felker @ 2013-12-04 0:38 UTC (permalink / raw) To: Ondřej Bílka; +Cc: Mark Mentovai, libc-alpha On Wed, Dec 04, 2013 at 01:08:21AM +0100, OndÅej BÃlka wrote: > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: > > When the close system call is interrupted by a signal, the state of its > > file descriptor argument is not specified[1]. On Linux, a close that > > fails with EINTR must not be restarted because the file descriptor is > > guaranteed to have been closed at that point[2]. Note that the kernel > > itself never restarts a close when SA_RESTART is set or when no > > user-space signal handler is present[3]. > > > This is linux problem, POSIX now says > > http://austingroupbugs.net/view.php?id=529 > > If close( ) is interrupted by a signal that is to be caught, then it > is unspecified whether it returns -1 with errno set to [EINTR] with > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] > [...] Assuming Linux will never switch to the correct POSIX EINTR behavior (the kernel folks are adamantly against it), would it be acceptable for glibc to fix up the resulting errno value from EINTR to EINPROGRESS, so that correct applications following POSIX will not loop on EINTR and introduce (extremely dangerous) double-close bugs? As long as the kernel folks are committed to keeping the current behavior, getting EINTR from the kernel essentially means EINPROGRESS and I think the replacement is justified. That's what I'm doing in musl. BTW if glibc ever fixes the cancellation races (bug #12683) handling close correctly there is important too (you can't act on cancellation when it interrupts a close syscall because the side effects have already completed, despite the errno value from the kernel, EINTR, making it appear that side effects did not occur). Rich ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2013-12-04 0:16 ` Ondřej Bílka 2013-12-04 0:38 ` Rich Felker @ 2013-12-05 17:35 ` Mark Mentovai 2016-12-05 14:49 ` Michael Kerrisk 2 siblings, 0 replies; 21+ messages in thread From: Mark Mentovai @ 2013-12-05 17:35 UTC (permalink / raw) To: Ondřej Bílka; +Cc: libc-alpha Ondřej Bílka wrote: > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: >> When the close system call is interrupted by a signal, the state of its >> file descriptor argument is not specified[1]. On Linux, a close that >> fails with EINTR must not be restarted because the file descriptor is >> guaranteed to have been closed at that point[2]. Note that the kernel >> itself never restarts a close when SA_RESTART is set or when no >> user-space signal handler is present[3]. >> > This is linux problem, POSIX now says > > http://austingroupbugs.net/view.php?id=529 > > If close( ) is interrupted by a signal that is to be caught, then it > is unspecified whether it returns -1 with errno set to [EINTR] with > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] > with fildes being closed, or returns 0 to indicate successful > completion; except that if POSIX_CLOSE_RESTART is defined as 0, then > the option of returning -1 with errno set to [EINTR] and fildes > remaining open shall not occur. If close() returns -1 with errno set > to [EINTR], it is unspecified whether fildes can subsequently be > passed to any function except close( ) or posix_close( ) without error. > For all other error situations (except for [EBADF] where fildes was > invalid), fildes shall be closed. If fildes was closed even though > the close operation is incomplete, the close operation shall continue > asynchronously and the process shall have no further ability to track > the completion or final status of the close operation. Linux (the kernel) doesn’t implement that behavior yet, and it may never. In the absence of a workaround in glibc to map close EINTR failures to EINPROGRESS, the glibc documentation currently recommends doing something dangerous on Linux. My proposed documentation patch doesn’t say that it’s never right to mix TEMP_FAILURE_RETRY with close, but it does say that they shouldn’t be combined on Linux. >> Because glibc is widely used on Linux, its documentation should state >> affirmatively that the TEMP_FAILURE_RETRY, which restarts interrupted >> system calls that fail with EINTR, is not to be used with close on >> Linux. Examples in glibc documentation should avoid recommending >> wrapping close with TEMP_FAILURE_RETRY. >> >> [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html >> [2] http://lkml.org/lkml/2005/9/10/129 >> [3] http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/?id=ee731f4f7880b09ca147008ab46ad4e5f72cb8b >> >> 2013-12-03 Mark Mentovai <mark@chromium.org> >> >> * manual/llio.texi (Opening and Closing Files): Document that >> TEMP_FAILURE_RETRY should not be used with close on Linux. >> (Duplicating Descriptors): Don't wrap close in TEMP_FAILURE_RETRY >> in example code. >> >> --- >> manual/llio.texi | 10 ++++------ >> 1 file changed, 4 insertions(+), 6 deletions(-) >> >> diff --git a/manual/llio.texi b/manual/llio.texi >> index b6c9260..f04a2cf 100644 >> --- a/manual/llio.texi >> +++ b/manual/llio.texi >> @@ -253,11 +253,9 @@ The @var{filedes} argument is not a valid file descriptor. >> @item EINTR >> The @code{close} call was interrupted by a signal. >> @xref{Interrupted Primitives}. >> -Here is an example of how to handle @code{EINTR} properly: >> - >> -@smallexample >> -TEMP_FAILURE_RETRY (close (desc)); >> -@end smallexample >> +On Linux, @code{close} will have closed its file descriptor argument even when >> +reporting @code{EINTR}. It is not safe to retry calling @code{close} in this >> +case, as would be done when wrapped in the @code{TEMP_FAILURE_RETRY} macro. >> >> @item ENOSPC >> @itemx EIO >> @@ -2765,7 +2763,7 @@ if (pid == 0) >> @dots{} >> file = TEMP_FAILURE_RETRY (open (filename, O_RDONLY)); >> dup2 (file, STDIN_FILENO); >> - TEMP_FAILURE_RETRY (close (file)); >> + close (file); >> execv (program, NULL); >> @} >> @end smallexample >> -- >> 1.8.3.4 ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2013-12-04 0:16 ` Ondřej Bílka 2013-12-04 0:38 ` Rich Felker 2013-12-05 17:35 ` Mark Mentovai @ 2016-12-05 14:49 ` Michael Kerrisk 2016-12-05 16:11 ` Rich Felker 2 siblings, 1 reply; 21+ messages in thread From: Michael Kerrisk @ 2016-12-05 14:49 UTC (permalink / raw) To: Ondřej Bílka Cc: Mark Mentovai, libc-alpha, Michael Kerrisk-manpages, Rich Felker, Daniel Wagner For what it's worth, well after the fact... On Wed, Dec 4, 2013 at 1:08 AM, Ondřej Bílka <neleai@seznam.cz> wrote: > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: >> When the close system call is interrupted by a signal, the state of its >> file descriptor argument is not specified[1]. On Linux, a close that >> fails with EINTR must not be restarted because the file descriptor is >> guaranteed to have been closed at that point[2]. Note that the kernel >> itself never restarts a close when SA_RESTART is set or when no >> user-space signal handler is present[3]. >> > This is linux problem, POSIX now says > > http://austingroupbugs.net/view.php?id=529 > > If close( ) is interrupted by a signal that is to be caught, then it > is unspecified whether it returns -1 with errno set to [EINTR] with > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] > with fildes being closed, or returns 0 to indicate successful > completion; except that if POSIX_CLOSE_RESTART is defined as 0, then > the option of returning -1 with errno set to [EINTR] and fildes > remaining open shall not occur. If close() returns -1 with errno set > to [EINTR], it is unspecified whether fildes can subsequently be > passed to any function except close( ) or posix_close( ) without error. > For all other error situations (except for [EBADF] where fildes was > invalid), fildes shall be closed. If fildes was closed even though > the close operation is incomplete, the close operation shall continue > asynchronously and the process shall have no further ability to track > the completion or final status of the close operation. Yes, but POSIX never said that. That was a proposal that was discussed, that subsequently got shot down... Older POSIX.1 was wrong. It's worth reading that entire Austin bug for the subsequent discussion. POSIX.1-2016 says under close() If close() is interrupted by a signal that is to be caught, it shall return −1 with errno set to [EINTR] and the state of fildes is unspecified. If an I/O error occurred while reading from or writing to the file system during close(), it may return −1 with errno set to [EIO]; if this error is returned, the state of fildes is unspecified. (The only three errors mandated in POSIX.1-2016 for close() are EINTR, EIO, and EBADF.) My takeaway from the above POSIX text is that it's perfectly legitimate for an implementation to say that retrying close() after *any* error is the wrong thing to do. Linux does this. So does FreeBSD, where the man page says: In case of any error except EBADF, the supplied file descriptor is deallocated and therefore is no longer valid. And according to a claim in the thread here: https://news.ycombinator.com/item?id=3363884 , ancient AIX also explicitly documented that the FD was closed in an EINTR error was returned. This looks to be confirmed in http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/close.htm And from the look of http://austingroupbugs.net/view.php?id=529#c1200 , the plan in the future is that POSIX will allow even more flexibility to an implementation in the next major release (who knows when). >> Because glibc is widely used on Linux, its documentation should state >> affirmatively that the TEMP_FAILURE_RETRY, which restarts interrupted >> system calls that fail with EINTR, is not to be used with close on >> Linux. Examples in glibc documentation should avoid recommending >> wrapping close with TEMP_FAILURE_RETRY. >> >> [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html >> [2] http://lkml.org/lkml/2005/9/10/129 >> [3] http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/?id=ee731f4f7880b09ca147008ab46ad4e5f72cb8b >> >> 2013-12-03 Mark Mentovai <mark@chromium.org> >> >> * manual/llio.texi (Opening and Closing Files): Document that >> TEMP_FAILURE_RETRY should not be used with close on Linux. >> (Duplicating Descriptors): Don't wrap close in TEMP_FAILURE_RETRY >> in example code. This patch of Mark's really should be applied in some form, I think. The glibc manual is currently advising users to do something actively dangerous on at least two popular systems, and it has no justification in current POSIX. I'm just in the process of beefing up the Linux close man page on this subject to say: Not checking the return value of close() is a common but neverthe‐ less serious programming error. It is quite possible that errors on a previous write(2) operation are first reported at the final close(). Not checking the return value when closing the file may lead to silent loss of data. This can especially be observed with NFS and with disk quota. Note, however, that the return value should be used only for diag‐ nostics. Retrying the close() after an error is the wrong thing to do, since this may cause a reused file descriptor from another thread to be closed. (The kernel releases the file descriptor early in the close operation, freeing it for reuse; the steps that may return an error, such as flushing data to disk, occur only later in the close operation.) In particular, close() should not be retried after an EINTR error. (POSIX.1 says: "If close() is interrupted by a signal that is to be caught, it shall return -1 with errno set to EINTR and the state of fildes is unspecified.") Careful users who want to know about I/O errors may precede close() with a call to fsync(2). Cheers, Michael >> >> --- >> manual/llio.texi | 10 ++++------ >> 1 file changed, 4 insertions(+), 6 deletions(-) >> >> diff --git a/manual/llio.texi b/manual/llio.texi >> index b6c9260..f04a2cf 100644 >> --- a/manual/llio.texi >> +++ b/manual/llio.texi >> @@ -253,11 +253,9 @@ The @var{filedes} argument is not a valid file descriptor. >> @item EINTR >> The @code{close} call was interrupted by a signal. >> @xref{Interrupted Primitives}. >> -Here is an example of how to handle @code{EINTR} properly: >> - >> -@smallexample >> -TEMP_FAILURE_RETRY (close (desc)); >> -@end smallexample >> +On Linux, @code{close} will have closed its file descriptor argument even when >> +reporting @code{EINTR}. It is not safe to retry calling @code{close} in this >> +case, as would be done when wrapped in the @code{TEMP_FAILURE_RETRY} macro. >> >> @item ENOSPC >> @itemx EIO >> @@ -2765,7 +2763,7 @@ if (pid == 0) >> @dots{} >> file = TEMP_FAILURE_RETRY (open (filename, O_RDONLY)); >> dup2 (file, STDIN_FILENO); >> - TEMP_FAILURE_RETRY (close (file)); >> + close (file); >> execv (program, NULL); >> @} >> @end smallexample >> -- >> 1.8.3.4 > ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 14:49 ` Michael Kerrisk @ 2016-12-05 16:11 ` Rich Felker 2016-12-05 16:18 ` Michael Kerrisk 0 siblings, 1 reply; 21+ messages in thread From: Rich Felker @ 2016-12-05 16:11 UTC (permalink / raw) To: Michael Kerrisk Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner On Mon, Dec 05, 2016 at 03:48:56PM +0100, Michael Kerrisk wrote: > For what it's worth, well after the fact... > > On Wed, Dec 4, 2013 at 1:08 AM, OndÅej BÃlka <neleai@seznam.cz> wrote: > > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: > >> When the close system call is interrupted by a signal, the state of its > >> file descriptor argument is not specified[1]. On Linux, a close that > >> fails with EINTR must not be restarted because the file descriptor is > >> guaranteed to have been closed at that point[2]. Note that the kernel > >> itself never restarts a close when SA_RESTART is set or when no > >> user-space signal handler is present[3]. > >> > > This is linux problem, POSIX now says > > > > http://austingroupbugs.net/view.php?id=529 > > > > If close( ) is interrupted by a signal that is to be caught, then it > > is unspecified whether it returns -1 with errno set to [EINTR] with > > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] > > with fildes being closed, or returns 0 to indicate successful > > completion; except that if POSIX_CLOSE_RESTART is defined as 0, then > > the option of returning -1 with errno set to [EINTR] and fildes > > remaining open shall not occur. If close() returns -1 with errno set > > to [EINTR], it is unspecified whether fildes can subsequently be > > passed to any function except close( ) or posix_close( ) without error. > > For all other error situations (except for [EBADF] where fildes was > > invalid), fildes shall be closed. If fildes was closed even though > > the close operation is incomplete, the close operation shall continue > > asynchronously and the process shall have no further ability to track > > the completion or final status of the close operation. > > Yes, but POSIX never said that. That was a proposal that was > discussed, that subsequently got shot down... It was not shot down. It was accepted for inclusion in the next issue of POSIX. 2016 is not a new issue; it's a TC for POSIX-2008, and cannot include non-bugfix changes. Rich ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:11 ` Rich Felker @ 2016-12-05 16:18 ` Michael Kerrisk 2016-12-05 16:23 ` Rich Felker 0 siblings, 1 reply; 21+ messages in thread From: Michael Kerrisk @ 2016-12-05 16:18 UTC (permalink / raw) To: Rich Felker Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner Hi, On Mon, Dec 5, 2016 at 5:11 PM, Rich Felker <dalias@aerifal.cx> wrote: > On Mon, Dec 05, 2016 at 03:48:56PM +0100, Michael Kerrisk wrote: >> For what it's worth, well after the fact... >> >> On Wed, Dec 4, 2013 at 1:08 AM, Ondřej Bílka <neleai@seznam.cz> wrote: >> > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: >> >> When the close system call is interrupted by a signal, the state of its >> >> file descriptor argument is not specified[1]. On Linux, a close that >> >> fails with EINTR must not be restarted because the file descriptor is >> >> guaranteed to have been closed at that point[2]. Note that the kernel >> >> itself never restarts a close when SA_RESTART is set or when no >> >> user-space signal handler is present[3]. >> >> >> > This is linux problem, POSIX now says >> > >> > http://austingroupbugs.net/view.php?id=529 >> > >> > If close( ) is interrupted by a signal that is to be caught, then it >> > is unspecified whether it returns -1 with errno set to [EINTR] with >> > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] >> > with fildes being closed, or returns 0 to indicate successful >> > completion; except that if POSIX_CLOSE_RESTART is defined as 0, then >> > the option of returning -1 with errno set to [EINTR] and fildes >> > remaining open shall not occur. If close() returns -1 with errno set >> > to [EINTR], it is unspecified whether fildes can subsequently be >> > passed to any function except close( ) or posix_close( ) without error. >> > For all other error situations (except for [EBADF] where fildes was >> > invalid), fildes shall be closed. If fildes was closed even though >> > the close operation is incomplete, the close operation shall continue >> > asynchronously and the process shall have no further ability to track >> > the completion or final status of the close operation. >> >> Yes, but POSIX never said that. That was a proposal that was >> discussed, that subsequently got shot down... > > It was not shot down. It was accepted for inclusion in the next issue > of POSIX. 2016 is not a new issue; it's a TC for POSIX-2008, and > cannot include non-bugfix changes. You're right. I misread the order of entries in bug (was looking at an older proposal that was shot down), and mismatched with what Ondrej quoted. But the point is still the same. Current POSIX.1 permits the Linux behavior, and future POSIX will too. So, the glibc manual still should get Mark's fix, I'd say. Cheers, Michael ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:18 ` Michael Kerrisk @ 2016-12-05 16:23 ` Rich Felker 2016-12-05 16:27 ` Michael Kerrisk 2016-12-05 16:32 ` Paul Eggert 0 siblings, 2 replies; 21+ messages in thread From: Rich Felker @ 2016-12-05 16:23 UTC (permalink / raw) To: Michael Kerrisk Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner On Mon, Dec 05, 2016 at 05:18:28PM +0100, Michael Kerrisk wrote: > Hi, > > On Mon, Dec 5, 2016 at 5:11 PM, Rich Felker <dalias@aerifal.cx> wrote: > > On Mon, Dec 05, 2016 at 03:48:56PM +0100, Michael Kerrisk wrote: > >> For what it's worth, well after the fact... > >> > >> On Wed, Dec 4, 2013 at 1:08 AM, OndÅej BÃlka <neleai@seznam.cz> wrote: > >> > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: > >> >> When the close system call is interrupted by a signal, the state of its > >> >> file descriptor argument is not specified[1]. On Linux, a close that > >> >> fails with EINTR must not be restarted because the file descriptor is > >> >> guaranteed to have been closed at that point[2]. Note that the kernel > >> >> itself never restarts a close when SA_RESTART is set or when no > >> >> user-space signal handler is present[3]. > >> >> > >> > This is linux problem, POSIX now says > >> > > >> > http://austingroupbugs.net/view.php?id=529 > >> > > >> > If close( ) is interrupted by a signal that is to be caught, then it > >> > is unspecified whether it returns -1 with errno set to [EINTR] with > >> > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] > >> > with fildes being closed, or returns 0 to indicate successful > >> > completion; except that if POSIX_CLOSE_RESTART is defined as 0, then > >> > the option of returning -1 with errno set to [EINTR] and fildes > >> > remaining open shall not occur. If close() returns -1 with errno set > >> > to [EINTR], it is unspecified whether fildes can subsequently be > >> > passed to any function except close( ) or posix_close( ) without error.. > >> > For all other error situations (except for [EBADF] where fildes was > >> > invalid), fildes shall be closed. If fildes was closed even though > >> > the close operation is incomplete, the close operation shall continue > >> > asynchronously and the process shall have no further ability to track > >> > the completion or final status of the close operation. > >> > >> Yes, but POSIX never said that. That was a proposal that was > >> discussed, that subsequently got shot down... > > > > It was not shot down. It was accepted for inclusion in the next issue > > of POSIX. 2016 is not a new issue; it's a TC for POSIX-2008, and > > cannot include non-bugfix changes. > > You're right. I misread the order of entries in bug (was looking at an > older proposal that was shot down), and mismatched with what Ondrej > quoted. > > But the point is still the same. Current POSIX.1 permits the Linux > behavior, and future POSIX will too. So, the glibc manual still should > get Mark's fix, I'd say. No, POSIX-future does not permit the Linux behavior. If EINTR is returned, the fd must still be "open" (not re-assignable, compatible with calling close on it again, though it may be in a partially-closed and unusable state). If the fd has been deallocated such that it's not safe to call close on it again, close must return some value other than EINTR; EINPROGRESS is added as the canonical error for the case where closing is not complete and happens in the background. Rich ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:23 ` Rich Felker @ 2016-12-05 16:27 ` Michael Kerrisk 2016-12-05 16:34 ` Rich Felker 2016-12-05 16:32 ` Paul Eggert 1 sibling, 1 reply; 21+ messages in thread From: Michael Kerrisk @ 2016-12-05 16:27 UTC (permalink / raw) To: Rich Felker Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner On Mon, Dec 5, 2016 at 5:22 PM, Rich Felker <dalias@aerifal.cx> wrote: > On Mon, Dec 05, 2016 at 05:18:28PM +0100, Michael Kerrisk wrote: >> Hi, >> >> On Mon, Dec 5, 2016 at 5:11 PM, Rich Felker <dalias@aerifal.cx> wrote: >> > On Mon, Dec 05, 2016 at 03:48:56PM +0100, Michael Kerrisk wrote: >> >> For what it's worth, well after the fact... >> >> >> >> On Wed, Dec 4, 2013 at 1:08 AM, Ondřej Bílka <neleai@seznam.cz> wrote: >> >> > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: >> >> >> When the close system call is interrupted by a signal, the state of its >> >> >> file descriptor argument is not specified[1]. On Linux, a close that >> >> >> fails with EINTR must not be restarted because the file descriptor is >> >> >> guaranteed to have been closed at that point[2]. Note that the kernel >> >> >> itself never restarts a close when SA_RESTART is set or when no >> >> >> user-space signal handler is present[3]. >> >> >> >> >> > This is linux problem, POSIX now says >> >> > >> >> > http://austingroupbugs.net/view.php?id=529 >> >> > >> >> > If close( ) is interrupted by a signal that is to be caught, then it >> >> > is unspecified whether it returns -1 with errno set to [EINTR] with >> >> > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] >> >> > with fildes being closed, or returns 0 to indicate successful >> >> > completion; except that if POSIX_CLOSE_RESTART is defined as 0, then >> >> > the option of returning -1 with errno set to [EINTR] and fildes >> >> > remaining open shall not occur. If close() returns -1 with errno set >> >> > to [EINTR], it is unspecified whether fildes can subsequently be >> >> > passed to any function except close( ) or posix_close( ) without error.. >> >> > For all other error situations (except for [EBADF] where fildes was >> >> > invalid), fildes shall be closed. If fildes was closed even though >> >> > the close operation is incomplete, the close operation shall continue >> >> > asynchronously and the process shall have no further ability to track >> >> > the completion or final status of the close operation. >> >> >> >> Yes, but POSIX never said that. That was a proposal that was >> >> discussed, that subsequently got shot down... >> > >> > It was not shot down. It was accepted for inclusion in the next issue >> > of POSIX. 2016 is not a new issue; it's a TC for POSIX-2008, and >> > cannot include non-bugfix changes. >> >> You're right. I misread the order of entries in bug (was looking at an >> older proposal that was shot down), and mismatched with what Ondrej >> quoted. >> >> But the point is still the same. Current POSIX.1 permits the Linux >> behavior, and future POSIX will too. So, the glibc manual still should >> get Mark's fix, I'd say. > > No, POSIX-future does not permit the Linux behavior. If EINTR is > returned, the fd must still be "open" (not re-assignable, compatible > with calling close on it again, though it may be in a partially-closed > and unusable state). If the fd has been deallocated such that it's not > safe to call close on it again, close must return some value other > than EINTR; EINPROGRESS is added as the canonical error for the case > where closing is not complete and happens in the background. Yes, you got me. I went away and reread this in the time you wrote the mail, and came to the same conclusion. So, the summary looks like this, AFAICT. Current POSIX permits the Linux behavior. Future POSIX proposes to make a change that contradicts the behavior of at least three existing implementations (Linux, FreeBSD, and AIX). That doesn't seem right. What have I missed? Cheers, Michael ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:27 ` Michael Kerrisk @ 2016-12-05 16:34 ` Rich Felker 2016-12-05 16:41 ` Michael Kerrisk (man-pages) 0 siblings, 1 reply; 21+ messages in thread From: Rich Felker @ 2016-12-05 16:34 UTC (permalink / raw) To: Michael Kerrisk Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner On Mon, Dec 05, 2016 at 05:27:23PM +0100, Michael Kerrisk wrote: > On Mon, Dec 5, 2016 at 5:22 PM, Rich Felker <dalias@aerifal.cx> wrote: > > On Mon, Dec 05, 2016 at 05:18:28PM +0100, Michael Kerrisk wrote: > >> Hi, > >> > >> On Mon, Dec 5, 2016 at 5:11 PM, Rich Felker <dalias@aerifal.cx> wrote: > >> > On Mon, Dec 05, 2016 at 03:48:56PM +0100, Michael Kerrisk wrote: > >> >> For what it's worth, well after the fact... > >> >> > >> >> On Wed, Dec 4, 2013 at 1:08 AM, OndÅej BÃlka <neleai@seznam..cz> wrote: > >> >> > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: > >> >> >> When the close system call is interrupted by a signal, the state of its > >> >> >> file descriptor argument is not specified[1]. On Linux, a close that > >> >> >> fails with EINTR must not be restarted because the file descriptor is > >> >> >> guaranteed to have been closed at that point[2]. Note that the kernel > >> >> >> itself never restarts a close when SA_RESTART is set or when no > >> >> >> user-space signal handler is present[3]. > >> >> >> > >> >> > This is linux problem, POSIX now says > >> >> > > >> >> > http://austingroupbugs.net/view.php?id=529 > >> >> > > >> >> > If close( ) is interrupted by a signal that is to be caught, then it > >> >> > is unspecified whether it returns -1 with errno set to [EINTR] with > >> >> > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] > >> >> > with fildes being closed, or returns 0 to indicate successful > >> >> > completion; except that if POSIX_CLOSE_RESTART is defined as 0, then > >> >> > the option of returning -1 with errno set to [EINTR] and fildes > >> >> > remaining open shall not occur. If close() returns -1 with errno set > >> >> > to [EINTR], it is unspecified whether fildes can subsequently be > >> >> > passed to any function except close( ) or posix_close( ) without error.. > >> >> > For all other error situations (except for [EBADF] where fildes was > >> >> > invalid), fildes shall be closed. If fildes was closed even though > >> >> > the close operation is incomplete, the close operation shall continue > >> >> > asynchronously and the process shall have no further ability to track > >> >> > the completion or final status of the close operation. > >> >> > >> >> Yes, but POSIX never said that. That was a proposal that was > >> >> discussed, that subsequently got shot down... > >> > > >> > It was not shot down. It was accepted for inclusion in the next issue > >> > of POSIX. 2016 is not a new issue; it's a TC for POSIX-2008, and > >> > cannot include non-bugfix changes. > >> > >> You're right. I misread the order of entries in bug (was looking at an > >> older proposal that was shot down), and mismatched with what Ondrej > >> quoted. > >> > >> But the point is still the same. Current POSIX.1 permits the Linux > >> behavior, and future POSIX will too. So, the glibc manual still should > >> get Mark's fix, I'd say. > > > > No, POSIX-future does not permit the Linux behavior. If EINTR is > > returned, the fd must still be "open" (not re-assignable, compatible > > with calling close on it again, though it may be in a partially-closed > > and unusable state). If the fd has been deallocated such that it's not > > safe to call close on it again, close must return some value other > > than EINTR; EINPROGRESS is added as the canonical error for the case > > where closing is not complete and happens in the background. > > Yes, you got me. I went away and reread this in the time you wrote the > mail, and came to the same conclusion. > > So, the summary looks like this, AFAICT. Current POSIX permits the > Linux behavior. Future POSIX proposes to make a change that > contradicts the behavior of at least three existing implementations > (Linux, FreeBSD, and AIX). That doesn't seem right. What have I > missed? The fact that these existing implementations were inconsistent with what EINTR means everywhere else ("no significant side effect has occurred yet from the call; if there are significant side effects, e.g. partial write, semaphore decremented, etc. the call returns the proper success value") and incompatible with the requirement that the side effects of a cancellation point on thread cancellation are required to be the same (almost-nothing) as the side effects on EINTR. In order to have adopted the Linux kernel behavior of close, POSIX would have had to special-case cancellation behavior of close() in a way that differs from every other cancellation point, and would have had to contradict the historical behavior of other implementations that actually got this (close/EINTR) right. Rich ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:34 ` Rich Felker @ 2016-12-05 16:41 ` Michael Kerrisk (man-pages) 2016-12-05 16:50 ` Rich Felker 0 siblings, 1 reply; 21+ messages in thread From: Michael Kerrisk (man-pages) @ 2016-12-05 16:41 UTC (permalink / raw) To: Rich Felker Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner Hello Rich On 5 December 2016 at 17:34, Rich Felker <dalias@aerifal.cx> wrote: > On Mon, Dec 05, 2016 at 05:27:23PM +0100, Michael Kerrisk wrote: >> On Mon, Dec 5, 2016 at 5:22 PM, Rich Felker <dalias@aerifal.cx> wrote: >> > On Mon, Dec 05, 2016 at 05:18:28PM +0100, Michael Kerrisk wrote: >> >> Hi, >> >> >> >> On Mon, Dec 5, 2016 at 5:11 PM, Rich Felker <dalias@aerifal.cx> wrote: >> >> > On Mon, Dec 05, 2016 at 03:48:56PM +0100, Michael Kerrisk wrote: >> >> >> For what it's worth, well after the fact... >> >> >> >> >> >> On Wed, Dec 4, 2013 at 1:08 AM, Ondřej Bílka <neleai@seznam..cz> wrote: >> >> >> > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: >> >> >> >> When the close system call is interrupted by a signal, the state of its >> >> >> >> file descriptor argument is not specified[1]. On Linux, a close that >> >> >> >> fails with EINTR must not be restarted because the file descriptor is >> >> >> >> guaranteed to have been closed at that point[2]. Note that the kernel >> >> >> >> itself never restarts a close when SA_RESTART is set or when no >> >> >> >> user-space signal handler is present[3]. >> >> >> >> >> >> >> > This is linux problem, POSIX now says >> >> >> > >> >> >> > http://austingroupbugs.net/view.php?id=529 >> >> >> > >> >> >> > If close( ) is interrupted by a signal that is to be caught, then it >> >> >> > is unspecified whether it returns -1 with errno set to [EINTR] with >> >> >> > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] >> >> >> > with fildes being closed, or returns 0 to indicate successful >> >> >> > completion; except that if POSIX_CLOSE_RESTART is defined as 0, then >> >> >> > the option of returning -1 with errno set to [EINTR] and fildes >> >> >> > remaining open shall not occur. If close() returns -1 with errno set >> >> >> > to [EINTR], it is unspecified whether fildes can subsequently be >> >> >> > passed to any function except close( ) or posix_close( ) without error.. >> >> >> > For all other error situations (except for [EBADF] where fildes was >> >> >> > invalid), fildes shall be closed. If fildes was closed even though >> >> >> > the close operation is incomplete, the close operation shall continue >> >> >> > asynchronously and the process shall have no further ability to track >> >> >> > the completion or final status of the close operation. >> >> >> >> >> >> Yes, but POSIX never said that. That was a proposal that was >> >> >> discussed, that subsequently got shot down... >> >> > >> >> > It was not shot down. It was accepted for inclusion in the next issue >> >> > of POSIX. 2016 is not a new issue; it's a TC for POSIX-2008, and >> >> > cannot include non-bugfix changes. >> >> >> >> You're right. I misread the order of entries in bug (was looking at an >> >> older proposal that was shot down), and mismatched with what Ondrej >> >> quoted. >> >> >> >> But the point is still the same. Current POSIX.1 permits the Linux >> >> behavior, and future POSIX will too. So, the glibc manual still should >> >> get Mark's fix, I'd say. >> > >> > No, POSIX-future does not permit the Linux behavior. If EINTR is >> > returned, the fd must still be "open" (not re-assignable, compatible >> > with calling close on it again, though it may be in a partially-closed >> > and unusable state). If the fd has been deallocated such that it's not >> > safe to call close on it again, close must return some value other >> > than EINTR; EINPROGRESS is added as the canonical error for the case >> > where closing is not complete and happens in the background. >> >> Yes, you got me. I went away and reread this in the time you wrote the >> mail, and came to the same conclusion. >> >> So, the summary looks like this, AFAICT. Current POSIX permits the >> Linux behavior. Future POSIX proposes to make a change that >> contradicts the behavior of at least three existing implementations >> (Linux, FreeBSD, and AIX). That doesn't seem right. What have I >> missed? > > The fact that these existing implementations were inconsistent with > what EINTR means everywhere else ("no significant side effect has > occurred yet from the call; if there are significant side effects, > e.g. partial write, semaphore decremented, etc. the call returns the > proper success value") and incompatible with the requirement that the > side effects of a cancellation point on thread cancellation are > required to be the same (almost-nothing) as the side effects on EINTR. > In order to have adopted the Linux kernel behavior of close, POSIX > would have had to special-case cancellation behavior of close() in a > way that differs from every other cancellation point, and would have > had to contradict the historical behavior of other implementations > that actually got this (close/EINTR) right. I didn't miss that ;-). I understand that in most other places, EINTR means something else. But already, POSIX is special casing close(). This is not "Linux kernel behavior"; this is "Linux kernel and free BSD kernel and AIX kernel behavior. Surely, POSIX.1 won't just by fiat say that the existing implementations are broken? Cheers, Michael -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:41 ` Michael Kerrisk (man-pages) @ 2016-12-05 16:50 ` Rich Felker 2016-12-06 9:57 ` Michael Kerrisk (man-pages) 0 siblings, 1 reply; 21+ messages in thread From: Rich Felker @ 2016-12-05 16:50 UTC (permalink / raw) To: Michael Kerrisk (man-pages) Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner On Mon, Dec 05, 2016 at 05:40:48PM +0100, Michael Kerrisk (man-pages) wrote: > Hello Rich > > On 5 December 2016 at 17:34, Rich Felker <dalias@aerifal.cx> wrote: > > On Mon, Dec 05, 2016 at 05:27:23PM +0100, Michael Kerrisk wrote: > >> On Mon, Dec 5, 2016 at 5:22 PM, Rich Felker <dalias@aerifal.cx> wrote: > >> > On Mon, Dec 05, 2016 at 05:18:28PM +0100, Michael Kerrisk wrote: > >> >> Hi, > >> >> > >> >> On Mon, Dec 5, 2016 at 5:11 PM, Rich Felker <dalias@aerifal.cx> wrote: > >> >> > On Mon, Dec 05, 2016 at 03:48:56PM +0100, Michael Kerrisk wrote: > >> >> >> For what it's worth, well after the fact... > >> >> >> > >> >> >> On Wed, Dec 4, 2013 at 1:08 AM, OndÅej BÃlka <neleai@seznam..cz> wrote: > >> >> >> > On Tue, Dec 03, 2013 at 01:05:21PM -0500, Mark Mentovai wrote: > >> >> >> >> When the close system call is interrupted by a signal, the state of its > >> >> >> >> file descriptor argument is not specified[1]. On Linux, a close that > >> >> >> >> fails with EINTR must not be restarted because the file descriptor is > >> >> >> >> guaranteed to have been closed at that point[2]. Note that the kernel > >> >> >> >> itself never restarts a close when SA_RESTART is set or when no > >> >> >> >> user-space signal handler is present[3]. > >> >> >> >> > >> >> >> > This is linux problem, POSIX now says > >> >> >> > > >> >> >> > http://austingroupbugs.net/view.php?id=529 > >> >> >> > > >> >> >> > If close( ) is interrupted by a signal that is to be caught, then it > >> >> >> > is unspecified whether it returns -1 with errno set to [EINTR] with > >> >> >> > fildes remaining open, or returns -1 with errno set to [EINPROGRESS] > >> >> >> > with fildes being closed, or returns 0 to indicate successful > >> >> >> > completion; except that if POSIX_CLOSE_RESTART is defined as 0, then > >> >> >> > the option of returning -1 with errno set to [EINTR] and fildes > >> >> >> > remaining open shall not occur. If close() returns -1 with errno set > >> >> >> > to [EINTR], it is unspecified whether fildes can subsequently be > >> >> >> > passed to any function except close( ) or posix_close( ) without error.. > >> >> >> > For all other error situations (except for [EBADF] where fildes was > >> >> >> > invalid), fildes shall be closed. If fildes was closed even though > >> >> >> > the close operation is incomplete, the close operation shall continue > >> >> >> > asynchronously and the process shall have no further ability to track > >> >> >> > the completion or final status of the close operation. > >> >> >> > >> >> >> Yes, but POSIX never said that. That was a proposal that was > >> >> >> discussed, that subsequently got shot down... > >> >> > > >> >> > It was not shot down. It was accepted for inclusion in the next issue > >> >> > of POSIX. 2016 is not a new issue; it's a TC for POSIX-2008, and > >> >> > cannot include non-bugfix changes. > >> >> > >> >> You're right. I misread the order of entries in bug (was looking at an > >> >> older proposal that was shot down), and mismatched with what Ondrej > >> >> quoted. > >> >> > >> >> But the point is still the same. Current POSIX.1 permits the Linux > >> >> behavior, and future POSIX will too. So, the glibc manual still should > >> >> get Mark's fix, I'd say. > >> > > >> > No, POSIX-future does not permit the Linux behavior. If EINTR is > >> > returned, the fd must still be "open" (not re-assignable, compatible > >> > with calling close on it again, though it may be in a partially-closed > >> > and unusable state). If the fd has been deallocated such that it's not > >> > safe to call close on it again, close must return some value other > >> > than EINTR; EINPROGRESS is added as the canonical error for the case > >> > where closing is not complete and happens in the background. > >> > >> Yes, you got me. I went away and reread this in the time you wrote the > >> mail, and came to the same conclusion. > >> > >> So, the summary looks like this, AFAICT. Current POSIX permits the > >> Linux behavior. Future POSIX proposes to make a change that > >> contradicts the behavior of at least three existing implementations > >> (Linux, FreeBSD, and AIX). That doesn't seem right. What have I > >> missed? > > > > The fact that these existing implementations were inconsistent with > > what EINTR means everywhere else ("no significant side effect has > > occurred yet from the call; if there are significant side effects, > > e.g. partial write, semaphore decremented, etc. the call returns the > > proper success value") and incompatible with the requirement that the > > side effects of a cancellation point on thread cancellation are > > required to be the same (almost-nothing) as the side effects on EINTR. > > In order to have adopted the Linux kernel behavior of close, POSIX > > would have had to special-case cancellation behavior of close() in a > > way that differs from every other cancellation point, and would have > > had to contradict the historical behavior of other implementations > > that actually got this (close/EINTR) right. > > I didn't miss that ;-). I understand that in most other places, EINTR > means something else. But already, POSIX is special casing close(). > This is not "Linux kernel behavior"; this is "Linux kernel and free > BSD kernel and AIX kernel behavior. Surely, POSIX.1 won't just by fiat > say that the existing implementations are broken? Do you have another proposed way out? It was a bug that they ever allowed ambiguity; before POSIX had threads it didn't matter (well, not too much; it could still be an issue with signal handlers!), but after threads were added, it became unsafe to have any ambiguity whether a file descriptor remains open, because closing it again results in an extremely-dangerous double-close race -- these can lead to file corruption, file contents disclosure, and even arbitrary code execution. The only way to avoid that would be to live with possible fd leaks, which result in eventual fd exhaustion. Fortunately nobody is asking Linux, FreeBSD, and AIX to change a feature that people actually want, or in an incompatible way. EINTR in close is very rare (only possible with tape drives, other weird devices, and perhaps some NFS configurations), and when it does happen, it's unwanted anyway. Changing in an incompatible way -- returning EINTR with the fd still open -- would be one option, but it's not a good one. Instead they should just return EINPROGRESS or better yet 0. As discussed on the glibc bug tracker issue, 0 is probably best to avoid affecting applications that might treat unknown results as a write error at close time. There is perhaps one other course of action that POSIX could have taken: defining a macro, or a sysconf() value, to query whether the implementation has left the fd open when close returns with EINTR. I think this is a much worse solution, but at least it would have made it possible to write safe applications. Rich ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:50 ` Rich Felker @ 2016-12-06 9:57 ` Michael Kerrisk (man-pages) 2016-12-06 15:52 ` Rich Felker 0 siblings, 1 reply; 21+ messages in thread From: Michael Kerrisk (man-pages) @ 2016-12-06 9:57 UTC (permalink / raw) To: Rich Felker Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner, Michael Kerrisk Hello Rich, On 5 December 2016 at 17:50, Rich Felker <dalias@aerifal.cx> wrote: > On Mon, Dec 05, 2016 at 05:40:48PM +0100, Michael Kerrisk (man-pages) wrote: >> Hello Rich >> >> On 5 December 2016 at 17:34, Rich Felker <dalias@aerifal.cx> wrote: >> > On Mon, Dec 05, 2016 at 05:27:23PM +0100, Michael Kerrisk wrote: >> >> On Mon, Dec 5, 2016 at 5:22 PM, Rich Felker <dalias@aerifal.cx> wrote: >> >> > On Mon, Dec 05, 2016 at 05:18:28PM +0100, Michael Kerrisk wrote: [...] >> >> So, the summary looks like this, AFAICT. Current POSIX permits the >> >> Linux behavior. Future POSIX proposes to make a change that >> >> contradicts the behavior of at least three existing implementations >> >> (Linux, FreeBSD, and AIX). That doesn't seem right. What have I >> >> missed? >> > >> > The fact that these existing implementations were inconsistent with >> > what EINTR means everywhere else ("no significant side effect has >> > occurred yet from the call; if there are significant side effects, >> > e.g. partial write, semaphore decremented, etc. the call returns the >> > proper success value") and incompatible with the requirement that the >> > side effects of a cancellation point on thread cancellation are >> > required to be the same (almost-nothing) as the side effects on EINTR. >> > In order to have adopted the Linux kernel behavior of close, POSIX >> > would have had to special-case cancellation behavior of close() in a >> > way that differs from every other cancellation point, and would have >> > had to contradict the historical behavior of other implementations >> > that actually got this (close/EINTR) right. >> >> I didn't miss that ;-). I understand that in most other places, EINTR >> means something else. But already, POSIX is special casing close(). >> This is not "Linux kernel behavior"; this is "Linux kernel and free >> BSD kernel and AIX kernel behavior. Surely, POSIX.1 won't just by fiat >> say that the existing implementations are broken? > > Do you have another proposed way out? Perhaps: leave the current close() specification as is, and mandate only the new posix_close() with the desired behavior? > It was a bug that they ever > allowed ambiguity; Well, inasmuch as POSIX.1 generally standardizes existing behavior, the initial bug was the failure to account for existing implementation behavior of close()... > before POSIX had threads it didn't matter (well, > not too much; it could still be an issue with signal handlers!), but > after threads were added, it became unsafe to have any ambiguity > whether a file descriptor remains open, because closing it again > results in an extremely-dangerous double-close race -- these can lead > to file corruption, file contents disclosure, and even arbitrary code > execution. The only way to avoid that would be to live with possible > fd leaks, which result in eventual fd exhaustion. Well, the other way to do it would be to do what Linux and FreeBSD do: always close the FD, even when returning an error. But, I take it you mean what the standard should provide as a guarantee to portable applications. Ambiguity there is obviously not helpful. > Fortunately nobody is asking Linux, FreeBSD, and AIX to change a > feature that people actually want, or in an incompatible way. EINTR in > close is very rare (only possible with tape drives, other weird > devices, and perhaps some NFS configurations), and when it does > happen, it's unwanted anyway. Changing in an incompatible way -- > returning EINTR with the fd still open -- would be one option, but > it's not a good one. Instead they should just return EINPROGRESS or > better yet 0. Of the options you list, 0 does seem the best bet. > As discussed on the glibc bug tracker issue, 0 is > probably best to avoid affecting applications that might treat unknown > results as a write error at close time. > > There is perhaps one other course of action that POSIX could have > taken: defining a macro, or a sysconf() value, to query whether the > implementation has left the fd open when close returns with EINTR. I > think this is a much worse solution, but at least it would have made > it possible to write safe applications. Not so pretty, I agree. So, from what I understand, there's a future path for implementations and applications. But, some existing applications (ones developed on Linux/FreeBSD/AIX that know not to retry the close() on EINTR) will be declared broken. That doesn't seem good. Or do I still miss something? Also, there is a wider problem here, it seems to me. It is not just EINTR that is being special cased in close(). Linux and FreeBSD [1], and to some extent, AIX [2] special case *all* errors from close(). For Linux and FreeBSD, the FD must be considered closed for any error that is returned. AIX has the following text: If the FileDescriptor parameter refers to a device and the close subroutine actually results in a device close, and the device close routine returns an error, the error is returned to the application. However, the FileDescriptor parameter is considered closed and it may not be used in any subsequent calls. (The AIX man page documents only the errors EBADF and EINTR, but that text hints to me that other errors are also possible.) Also, I took a look at the illumos code base, which presumably does not differ greatly from historical Solaris on this point. It looks to me (closef(), closeandsetf()) that also on that system there are paths in close() where errors are returned but the FD is nevertheless closed. So it really does seem that POSIX.1 was specifying (and plans to again specify) behavior that is inconsistent with actual implementations. Thanks for your explanations, Rich. Cheers, Michael [1] https://www.freebsd.org/cgi/man.cgi?query=close&apropos=0&sektion=0&manpath=FreeBSD+10.3-RELEASE+and+Ports&arch=default&format=html#ERRORS [2] http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/close.htm -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-06 9:57 ` Michael Kerrisk (man-pages) @ 2016-12-06 15:52 ` Rich Felker 2016-12-06 22:43 ` Zack Weinberg 0 siblings, 1 reply; 21+ messages in thread From: Rich Felker @ 2016-12-06 15:52 UTC (permalink / raw) To: Michael Kerrisk (man-pages) Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner On Tue, Dec 06, 2016 at 10:57:16AM +0100, Michael Kerrisk (man-pages) wrote: > Hello Rich, > > On 5 December 2016 at 17:50, Rich Felker <dalias@aerifal.cx> wrote: > > On Mon, Dec 05, 2016 at 05:40:48PM +0100, Michael Kerrisk (man-pages) wrote: > >> Hello Rich > >> > >> On 5 December 2016 at 17:34, Rich Felker <dalias@aerifal.cx> wrote: > >> > On Mon, Dec 05, 2016 at 05:27:23PM +0100, Michael Kerrisk wrote: > >> >> On Mon, Dec 5, 2016 at 5:22 PM, Rich Felker <dalias@aerifal.cx> wrote: > >> >> > On Mon, Dec 05, 2016 at 05:18:28PM +0100, Michael Kerrisk wrote: > > [...] > > >> >> So, the summary looks like this, AFAICT. Current POSIX permits the > >> >> Linux behavior. Future POSIX proposes to make a change that > >> >> contradicts the behavior of at least three existing implementations > >> >> (Linux, FreeBSD, and AIX). That doesn't seem right. What have I > >> >> missed? > >> > > >> > The fact that these existing implementations were inconsistent with > >> > what EINTR means everywhere else ("no significant side effect has > >> > occurred yet from the call; if there are significant side effects, > >> > e.g. partial write, semaphore decremented, etc. the call returns the > >> > proper success value") and incompatible with the requirement that the > >> > side effects of a cancellation point on thread cancellation are > >> > required to be the same (almost-nothing) as the side effects on EINTR. > >> > In order to have adopted the Linux kernel behavior of close, POSIX > >> > would have had to special-case cancellation behavior of close() in a > >> > way that differs from every other cancellation point, and would have > >> > had to contradict the historical behavior of other implementations > >> > that actually got this (close/EINTR) right. > >> > >> I didn't miss that ;-). I understand that in most other places, EINTR > >> means something else. But already, POSIX is special casing close(). > >> This is not "Linux kernel behavior"; this is "Linux kernel and free > >> BSD kernel and AIX kernel behavior. Surely, POSIX.1 won't just by fiat > >> say that the existing implementations are broken? > > > > Do you have another proposed way out? > > Perhaps: leave the current close() specification as is, and mandate > only the new posix_close() with the desired behavior? I don't think leaving a serious bug in an interface that everyone uses and forcing programs to abandon the interface and use a new barely-known one in its place is a viable solution. > > It was a bug that they ever > > allowed ambiguity; > > Well, inasmuch as POSIX.1 generally standardizes existing behavior, > the initial bug was the failure to account for existing implementation > behavior of close()... There are many precedents for POSIX imposing new requirements where traditional/existing behavior had critical bugs. I can dig some up if you want. I see this as a very good thing. > > before POSIX had threads it didn't matter (well, > > not too much; it could still be an issue with signal handlers!), but > > after threads were added, it became unsafe to have any ambiguity > > whether a file descriptor remains open, because closing it again > > results in an extremely-dangerous double-close race -- these can lead > > to file corruption, file contents disclosure, and even arbitrary code > > execution. The only way to avoid that would be to live with possible > > fd leaks, which result in eventual fd exhaustion. > > Well, the other way to do it would be to do what Linux and FreeBSD do: > always close the FD, even when returning an error. But, I take it you > mean what the standard should provide as a guarantee to portable > applications. Ambiguity there is obviously not helpful. I was speaking from a portable application perspective, not from an implementation perspective. With the ambiguous spec, the application must accept the leak, since the double-close would be much worse. > > Fortunately nobody is asking Linux, FreeBSD, and AIX to change a > > feature that people actually want, or in an incompatible way. EINTR in > > close is very rare (only possible with tape drives, other weird > > devices, and perhaps some NFS configurations), and when it does > > happen, it's unwanted anyway. Changing in an incompatible way -- > > returning EINTR with the fd still open -- would be one option, but > > it's not a good one. Instead they should just return EINPROGRESS or > > better yet 0. > > Of the options you list, 0 does seem the best bet. > > > As discussed on the glibc bug tracker issue, 0 is > > probably best to avoid affecting applications that might treat unknown > > results as a write error at close time. > > > > There is perhaps one other course of action that POSIX could have > > taken: defining a macro, or a sysconf() value, to query whether the > > implementation has left the fd open when close returns with EINTR. I > > think this is a much worse solution, but at least it would have made > > it possible to write safe applications. > > Not so pretty, I agree. > > So, from what I understand, there's a future path for implementations > and applications. But, some existing applications (ones developed on > Linux/FreeBSD/AIX that know not to retry the close() on EINTR) will be > declared broken. That doesn't seem good. Or do I still miss something? They're only broken insomuch as they leak file descriptors on conforming implementations, which is exactly the situation now when these applications are run on implementations with the other (now POSIX-adopted) behavior. There is no regression. These applications were already making a non-portable assumption (because the standard did not offer them any way to avoid doign so). > Also, there is a wider problem here, it seems to me. It is not just > EINTR that is being special cased in close(). Linux and FreeBSD [1], > and to some extent, AIX [2] special case *all* errors from close(). > For Linux and FreeBSD, the FD must be considered closed for any error > that is returned. AIX has the following text: > > If the FileDescriptor parameter refers to a device and the > close subroutine actually results in a device close, and the > device close routine returns an error, the error is returned > to the application. However, the FileDescriptor parameter is > considered closed and it may not be used in any subsequent > calls. > > (The AIX man page documents only the errors EBADF and EINTR, but that > text hints to me that other errors are also possible.) POSIX-future imposes this requirement too. The accepted text contains: For all other error situations (except for [EBADF] where fildes was invalid), fildes shall be closed. Previously it was ambiguous for other errors too, which was a big problem. > Also, I took a look at the illumos code base, which presumably does > not differ greatly from historical Solaris on this point. It looks to > me (closef(), closeandsetf()) that also on that system there are paths > in close() where errors are returned but the FD is nevertheless > closed. So it really does seem that POSIX.1 was specifying (and plans > to again specify) behavior that is inconsistent with actual > implementations. I think you're assuming POSIX is imposing something opposite of what it's doing. The new text has filedes left open _only_ in the case of EINTR. For all other errors it's closed and available for reassignment on subsequent open, etc. Rich ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-06 15:52 ` Rich Felker @ 2016-12-06 22:43 ` Zack Weinberg 2016-12-06 23:58 ` Rich Felker 2016-12-07 12:37 ` Michael Kerrisk (man-pages) 0 siblings, 2 replies; 21+ messages in thread From: Zack Weinberg @ 2016-12-06 22:43 UTC (permalink / raw) To: libc-alpha, Michael Kerrisk (man-pages) On 12/06/2016 10:51 AM, Rich Felker wrote: >> Also, I took a look at the illumos code base, which presumably does >> not differ greatly from historical Solaris on this point. It looks to >> me (closef(), closeandsetf()) that also on that system there are paths >> in close() where errors are returned but the FD is nevertheless >> closed. So it really does seem that POSIX.1 was specifying (and plans >> to again specify) behavior that is inconsistent with actual >> implementations. > > I think you're assuming POSIX is imposing something opposite of what > it's doing. The new text has filedes left open _only_ in the case of > EINTR. For all other errors it's closed and available for reassignment > on subsequent open, etc. But that's still wrong! `fildes` MUST be closed even when EINTR is returned. That's what all existing implementations do (if I understood Michael correctly), and even if I've misunderstood that part, because *some* implementations do it, portable code has to assume that it's unsafe to retry the operation. So the only sane specification for POSIX to make is that the descriptor is closed. (No, new programs cannot assume that it's safe to retry, because new programs get run on old operating systems.) (Yes, this means delayed failures can get lost. Code that cares should've called `fsync` anyway. Also, the whole thing is moot if you use SA_RESTART on all your signals, which is the Right Thing for tons of other reasons.) ---- Regardless of what the specification does or doesn't say or will be corrected to say, what the *glibc manual* should say is clear, IMNSHO: don't retry close(). Proposed new text follows - it's not as emphatic as what Michael wrote for the manpages but I think it's sufficient. zw @comment unistd.h @comment POSIX.1 @deftypefun int close (int @var{filedes}) @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}} The function @code{close} closes the file descriptor @var{filedes}. Closing a file has the following consequences: @itemize @bullet @item The file descriptor is deallocated. @item Any record locks owned by the process on the file are unlocked. @item When all file descriptors associated with a pipe or FIFO have been closed, any unread data is discarded. @end itemize Closing a file does @emph{not} guarantee that all data has been successfully written to disk. If you need to make sure of this, you must call @code{fsync} before @code{close} (@pxref{Synchronizing I/O operations}). @code{close} never @emph{fails}; after any call to @code{close} returns, the file descriptor @var{filedes} has been closed and must not be used again. However, it may still report an error. It returns 0 if there was no error, and @math{-1} if an error occurred. The following @code{errno} error conditions are defined for this function: @table @code @item ENOSPC @itemx EIO @itemx EDQUOT These codes indicate an I/O error in an earlier call to @code{write} that appeared to succeed. @xref{I/O Primitives}, for details on their meaning. Because of these ``delayed failures,'' it is important to check for errors in @code{close}. @item EINTR The @code{close} call was interrupted by a signal. The only consequence of this is that a ``delayed failure'' may have been lost---the file descriptor has still been closed. You should @emph{not} retry the system call. @item EBADF The @var{filedes} argument was not an open file descriptor to begin with (and still isn't). @end table This function is a cancellation point in multi-threaded programs. This is a problem if the thread allocates some resources (like memory, file descriptors, semaphores or whatever) at the time @code{close} is called. If the thread gets canceled these resources stay allocated until the program ends. To avoid this, calls to @code{close} should be protected using cancellation handlers. @c ref pthread_cleanup_push / pthread_cleanup_pop @code{close} can close any type of file descriptor, no matter how it was opened. Therefore, there is no @code{close64}, as it is unnecessary. However, @code{FILE} objects must be closed using @code{fclose} instead (@pxref{Closing Streams}). @end deftypefun ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-06 22:43 ` Zack Weinberg @ 2016-12-06 23:58 ` Rich Felker 2016-12-07 12:16 ` Michael Kerrisk (man-pages) 2016-12-07 12:37 ` Michael Kerrisk (man-pages) 1 sibling, 1 reply; 21+ messages in thread From: Rich Felker @ 2016-12-06 23:58 UTC (permalink / raw) To: Zack Weinberg; +Cc: libc-alpha, Michael Kerrisk (man-pages) On Tue, Dec 06, 2016 at 05:42:57PM -0500, Zack Weinberg wrote: > On 12/06/2016 10:51 AM, Rich Felker wrote: > >> Also, I took a look at the illumos code base, which presumably does > >> not differ greatly from historical Solaris on this point. It looks to > >> me (closef(), closeandsetf()) that also on that system there are paths > >> in close() where errors are returned but the FD is nevertheless > >> closed. So it really does seem that POSIX.1 was specifying (and plans > >> to again specify) behavior that is inconsistent with actual > >> implementations. > > > > I think you're assuming POSIX is imposing something opposite of what > > it's doing. The new text has filedes left open _only_ in the case of > > EINTR. For all other errors it's closed and available for reassignment > > on subsequent open, etc. > > But that's still wrong! `fildes` MUST be closed even when EINTR is > returned. That's what all existing implementations do (if I understood > Michael correctly), It's not. It's what some (roughly half?) of implementations do, and it's inconsistent with the meaning of EINTR. Read the whole thread, as this has already been discussed in-depth; repeating it for latecomers is not useful. In any case, the practical path forward that avoids the issue entirely is never generating EINTR at all, so that applications don't have to deal with it. See https://sourceware.org/bugzilla/show_bug.cgi?id=14627 Rich ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-06 23:58 ` Rich Felker @ 2016-12-07 12:16 ` Michael Kerrisk (man-pages) 0 siblings, 0 replies; 21+ messages in thread From: Michael Kerrisk (man-pages) @ 2016-12-07 12:16 UTC (permalink / raw) To: Rich Felker, Zack Weinberg; +Cc: mtk.manpages, libc-alpha Rich, On 12/07/2016 12:58 AM, Rich Felker wrote: > On Tue, Dec 06, 2016 at 05:42:57PM -0500, Zack Weinberg wrote: >> On 12/06/2016 10:51 AM, Rich Felker wrote: >>>> Also, I took a look at the illumos code base, which presumably does >>>> not differ greatly from historical Solaris on this point. It looks to >>>> me (closef(), closeandsetf()) that also on that system there are paths >>>> in close() where errors are returned but the FD is nevertheless >>>> closed. So it really does seem that POSIX.1 was specifying (and plans >>>> to again specify) behavior that is inconsistent with actual >>>> implementations. >>> >>> I think you're assuming POSIX is imposing something opposite of what >>> it's doing. The new text has filedes left open _only_ in the case of >>> EINTR. For all other errors it's closed and available for reassignment >>> on subsequent open, etc. >> >> But that's still wrong! `fildes` MUST be closed even when EINTR is >> returned. That's what all existing implementations do (if I understood >> Michael correctly), > > It's not. It's what some (roughly half?) of implementations do, and Where do you get this number "half" from? That's far from what I've managed to divine so far. From my reading of various source code, and manual pages (for the benefit of others, see pasted message that I sent to the Austin-l mailing list yesterday; Zack, I'll loop you into that thread on my next reply), the situation is as follows. 1. Always close the FD, regardless of the error (including EINTR): Linux (verified from source) AIX (documented, and AIX 4.1.3 source) FreeBSD (from documentation and source) Historical System V R4 (from source) Solaris (from source) I've since taken a look at the NetBSD and OpenBSD code bases, and it appears that they do likewise. I assert this with less certainty though, since I've not spent so much time looking at these implementations. One of the other things that is clear, by the way, is that many of these systems did/do not accurately document what they do. And those that do, did so only recently: FreeBSD in 2012 and Linux (man-pages) in 2013. 2. Can return an EINTR while leaving the FD open: HP-UX (from documentation) 3. Unclear: Irix 6.5.5 (I looked at the source code. The Irix code is structured rather differently from other systems, and I couldn't really work out what goes on.) Of course, there are many other systems (now mostly irrelevant) that are not listed above, but from the above, "half" seems quite wide of the mark. > it's inconsistent with the meaning of EINTR. I don't really consider this statement to have much weight. The general argument that "EINTR is being treated inconsistently for close() (by contrast with other interfaces that return EINTR)" has little weight in the face of the following: 1. It appears that majority of implementations (including the majority of the currently relevant implementations) always close the FD, even in the case that EINTR returns. Furthermore, one could equally say that those implementations are treating EINTR consistently with all other errors from close(). 2. Future POSIX.1 (http://austingroupbugs.net/view.php?id=529#c1200) proposes to special case the meaning of failure return from close(). According to the proposal, even on errors (other than EINTR), close will close the FD (i.e., it will "succeed"). This is consistent (except for the EINTR detail) with the majority of implementations. But, if consistency is the argument,then it's worth noting that by this definition, the meaning of "failure" for close() is inconsistent with the meaning of "failure" for other interfaces, where "failure" generally means that the interface did not successfully complete the requested action. And then, in the middle of this special casing of the meaning of "failure" for close(), the POSIX.1 proposal is to special case one failure (EINTR) to mean something different from the other failures from close(). > Read the whole thread, as > this has already been discussed in-depth; repeating it for latecomers > is not useful. Yes, but a critical piece is absent from the Austin bug and Austin mailing list discussion, as far as I can see: namely, the rationale for changing the close() spec in one direction (forbidding that close() returns EINTR *and* closes the file descriptor) rather than another (forbidding the possibility that close() returns EINTR and leaves the FD open) that would seem more consistent with the majority of implementations, and would not render those implementations nonconforming according to future POSIX.1 (and would not render applications that depend on existing implementation behavior "broken"). > In any case, the practical path forward that avoids the issue entirely > is never generating EINTR at all, so that applications don't have to > deal with it. See https://sourceware.org/bugzilla/show_bug.cgi?id=14627 Yes, but this ignores the fact that a burden is placed on (most) implementations to fix a non-issue on those implementations and a burden is placed on application developers to modify code that works on the majority of implementations. And there is no clear advantage to this change versus the less burdensome requirement of forbidding the possibility that close() returns EINTR and leaves the FD open, which requires changes to a minority(?) of implementations, and no changes to applications. Cheers, Michael === Here's my message from yesterday to the austin-l list, for reference. I'm continuing that discussion later today, elaborating on some of the points made in this mail. -------- Forwarded Message -------- Subject: Some questions on bug 529 (fildes unspecified on close()'s [EINTR]) Date: Tue, 6 Dec 2016 14:50:23 +0100 From: Michael Kerrisk <mtk.manpages@gmail.com> To: austin-group-l@opengroup.org <austin-group-l@opengroup.org> CC: Rich Felker <dalias@aerifal.cx>, Michael Kerrisk-manpages <mtk.manpages@gmail.com>, Eric Blake <eblake@redhat.com>, Geoff Clare <gwc@opengroup.org> Hello all, Following a discussion [4][5] (and a bit of education for me, thanks to Rich Felker) on the GNU C Library (libc-alpha) mailing list, I have some questions about bug 529 [0]. 1. If I understand correctly, the proposed changes for Issue 8 will in effect declare to be broken those existing applications that treat EINTR from close() as "the file is closed". (I.e., per the proposed changes [7], implementations will not be allowed to have close() fail with EINTR while also closing the file.) However, those existing applications are behaving correctly in terms of what the implementations do. Is my understanding of the intentions of the Issue 8 changes correct? If yes, I presume the path is that such applications would be conformant to older POSIX, but won't be conformant to Issue 8. (Right?) 2. From the bug thread, I've missed something. I understand the argument that EINTR was being treated inconsistently for close() on Linux and other systems, but the thing is that implementations with the close() "EINTR means the file descriptor is closed" behavior exist, and seem even to be common. Why (given the variation in existing implementations) was the decision taken to change the specification for close() , instead of just adding a new posix_close() that addresses the problem? 3. [An observation, not a question] As far as I can tell, the Linux behavior for close() EINTR semantics is not an isolated case. One can see this in the FreeBSD close(2) manual page [1] and in the AIX [2] manual page. It seems also to be the norm for other implementations (see my next point). HP-UX claims [6] in the documentation to leave the file open on EINTR, but unfortunately, the source code isn't publicly available to verify this 4. The interpretation for bug 529 doesn't address a wider issue. On several implementations, the FD is always closed *for any error* that close() may return. That is what Linux does (the FD is released very early in the "close" processing, and errors may be reported afterward). It's also what FreeBSD does, as documented in its close(2) man page: In case of any error except EBADF, the supplied file descriptor is deallocated and therefore is no longer valid. (By the way, that text seems to have been added in FreeBSD 9.1, in early 2012, I presume to document existing behavior after someone read this Austin bug report.) For info, FreeBSD documents the following errors for close(): EBADF, EINTR, ENOSPC, and ECONNRESET. Looking at some historical source code (mostly from [3]) suggests that the "close() always closes regardless of error return" behavior has a long history, predating even POSIX.1-1990. For example, in SVR4 for x86 (from the file sysvr4.tar.bz2 at [3]), we see the following: === int close(uap, rvp) register struct closea *uap; rval_t *rvp; { file_t *fp; register int error; if (error = getf(uap->fdes, &fp)) return error; error = closef(fp); setf(uap->fdes, NULLFP); return error; } === In the above, getf() can return EBADF. The other errors are returned by closef(), but the file descriptor is deallocated regardless of errors by setf(). A similar pattern seems to have been preserved into at least late OpenSolaris days (verified from looking at the initial commit of the illumos source code). There we find the following in closeandsetf() (called by close()) error = closef(fp); setf(fd, newfp); return (error); Looking at the code of closef() in AIX 4.1.3 suggests that, as on on Linux and FreeBSD, the open file is always released, regardless of errors. For Irix, 6.5.5, I'm not sure (the code is not so easy to quickly read); it may be that it does return errors while leaving the FD open. So, my summary here is that many (perhaps most?) implementations are similar to Linux and FreeBSD, but this isn't currently addressed in POSIX, so far as I can tell. Should it be? Cheers, Michael [0] http://austingroupbugs.net/view.php?id=529 [1] https://www.freebsd.org/cgi/man.cgi?query=close&apropos=0&sektion=0&manpath=FreeBSD+10.3-RELEASE+and+Ports&arch=default&format=html#ERRORS [2] http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/close.htm [3] https://archive.org/download/various_operating_system_source_code [4] https://sourceware.org/ml/libc-alpha/2016-12/msg00110.html [5] https://sourceware.org/ml/libc-alpha/2016-12/msg00136.html [6] http://www.unix.com/man-page/hpux/2/close/ [7] http://austingroupbugs.net/view.php?id=529#c1200 -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-06 22:43 ` Zack Weinberg 2016-12-06 23:58 ` Rich Felker @ 2016-12-07 12:37 ` Michael Kerrisk (man-pages) 1 sibling, 0 replies; 21+ messages in thread From: Michael Kerrisk (man-pages) @ 2016-12-07 12:37 UTC (permalink / raw) To: Zack Weinberg, libc-alpha; +Cc: mtk.manpages On 12/06/2016 11:42 PM, Zack Weinberg wrote: > On 12/06/2016 10:51 AM, Rich Felker wrote: >>> Also, I took a look at the illumos code base, which presumably does >>> not differ greatly from historical Solaris on this point. It looks to >>> me (closef(), closeandsetf()) that also on that system there are paths >>> in close() where errors are returned but the FD is nevertheless >>> closed. So it really does seem that POSIX.1 was specifying (and plans >>> to again specify) behavior that is inconsistent with actual >>> implementations. >> >> I think you're assuming POSIX is imposing something opposite of what >> it's doing. The new text has filedes left open _only_ in the case of >> EINTR. For all other errors it's closed and available for reassignment >> on subsequent open, etc. > > But that's still wrong! `fildes` MUST be closed even when EINTR is > returned. That's what all existing implementations do (if I understood > Michael correctly), I believe it is "most (not all) implementations. > and even if I've misunderstood that part, because > *some* implementations do it, portable code has to assume that it's > unsafe to retry the operation. So the only sane specification for POSIX > to make is that the descriptor is closed. That's my opinion. > (No, new programs cannot assume that it's safe to retry, because new > programs get run on old operating systems.) Exactly. This is the sense in which I'd argue that the POSIX.1 proposal (to forbid an implementation from returning EINTR and close the FD) potentially worsens portability. > (Yes, this means delayed failures can get lost. Code that cares > should've called `fsync` anyway. Also, the whole thing is moot if you > use SA_RESTART on all your signals, which is the Right Thing for tons of > other reasons.) > > ---- > > Regardless of what the specification does or doesn't say or will be > corrected to say, what the *glibc manual* should say is clear, IMNSHO: > don't retry close(). Proposed new text follows - it's not as emphatic > as what Michael wrote for the manpages but I think it's sufficient. Yes, I still think the glibc manual needs fixing. But, by now, I've tried to be more nuanced in a further revision to the close(2) man page, which by now reads: A careful programmer will check the return value of close(), since it is quite possible that errors on a previous write(2) operation are reported only on the final close() that releases the open file description. Failing to check the return value when closing a file may lead to silent loss of data. This can especially be observed with NFS and with disk quota. Note, however, that a failure return should be used only for diagâ nostic purposes (i.e., a warning to the application that there may still be I/O pending or there may have been failed I/O) or remeâ dial purposes (e.g., writing the file once more or creating a backup). Retrying the close() after a failure return is the wrong thing to do, since this may cause a reused file descriptor from another thread to be closed. This can occur because the Linux kernel always releases the file descriptor early in the close operation, freeing it for reuse; the steps that may return an error, such as flushing data to the filesystem or device, occur only later in the close operation. Many other implementations similarly always close the file descriptor (except in the case of EBADF, meaning that the file descriptor was invalid) even if they subsequently report an error on return from close(). POSIX.1 is currently silent on this point, but there are plans to mandate this behavior in the next major release of the standard A careful programmer who wants to know about I/O errors may preâ cede close() with a call to fsync(2). The EINTR error is a somewhat special case. Regarding the EINTR error, POSIX.1-2013 says: If close() is interrupted by a signal that is to be caught, it shall return -1 with errno set to EINTR and the state of fildes is unspecified. This permits the behavior that occurs on Linux and many other implementations, where, as with other errors that may be reported by close(), the file descriptor is guaranteed to be closed. Howâ ever, it also permits another possibility: that the implementation returns an EINTR error and keeps the file descriptor open. (According to its documentation, HP-UX's close() does this.) The caller must then once more use close() to close the file descripâ tor, to avoid file descriptor leaks. This divergence in implemenâ tation behaviors provides a difficult hurdle for portable applicaâ tions, since on many implementations, close() must not be called again after an EINTR error, and on at least one, close() must be called again. There are plans to address this conundrum for the next major release of the POSIX.1 standard. (Excepting the first paragraph, all of the text there was added by me, and can be considered in the public domain if any of it is useful for inclusion in the glibc manual.) > @comment unistd.h > @comment POSIX.1 > @deftypefun int close (int @var{filedes}) > @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}} > The function @code{close} closes the file descriptor @var{filedes}. > Closing a file has the following consequences: > > @itemize @bullet > @item > The file descriptor is deallocated. > > @item > Any record locks owned by the process on the file are unlocked. > > @item > When all file descriptors associated with a pipe or FIFO have been closed, > any unread data is discarded. > @end itemize > > Closing a file does @emph{not} guarantee that all data has been > successfully written to disk. If you need to make sure of this, you > must call @code{fsync} before @code{close} (@pxref{Synchronizing I/O > operations}). > > @code{close} never @emph{fails}; after any call to @code{close} > returns, the file descriptor @var{filedes} has been closed and must > not be used again. However, it may still report an error. It returns > 0 if there was no error, and @math{-1} if an error occurred. The > following @code{errno} error conditions are defined for this function: > > @table @code > @item ENOSPC > @itemx EIO > @itemx EDQUOT > These codes indicate an I/O error in an earlier call to @code{write} > that appeared to succeed. @xref{I/O Primitives}, for details on their > meaning. Because of these ``delayed failures,'' it is important to > check for errors in @code{close}. > > @item EINTR > The @code{close} call was interrupted by a signal. The only > consequence of this is that a ``delayed failure'' may have been > lost---the file descriptor has still been closed. You should > @emph{not} retry the system call. > > @item EBADF > The @var{filedes} argument was not an open file descriptor to begin > with (and still isn't). > @end table > > This function is a cancellation point in multi-threaded programs. This > is a problem if the thread allocates some resources (like memory, file > descriptors, semaphores or whatever) at the time @code{close} is > called. If the thread gets canceled these resources stay allocated > until the program ends. To avoid this, calls to @code{close} should be > protected using cancellation handlers. > @c ref pthread_cleanup_push / pthread_cleanup_pop > > @code{close} can close any type of file descriptor, no matter how it > was opened. Therefore, there is no @code{close64}, as it is > unnecessary. However, @code{FILE} objects must be closed using > @code{fclose} instead (@pxref{Closing Streams}). > @end deftypefun While the above is accurate for glibc on Linux, and is also true for many other systems (AFAICT), I can see why there may be resistance to accepting it for the glibc manual. Maybe, some more nuanced text would be helpful. In any case the current manual text should still be changed, IMO. Cheers, Michael -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:23 ` Rich Felker 2016-12-05 16:27 ` Michael Kerrisk @ 2016-12-05 16:32 ` Paul Eggert 2016-12-05 16:39 ` Rich Felker 1 sibling, 1 reply; 21+ messages in thread From: Paul Eggert @ 2016-12-05 16:32 UTC (permalink / raw) To: Rich Felker, Michael Kerrisk Cc: Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner On 12/05/2016 08:22 AM, Rich Felker wrote: > POSIX-future does not permit the Linux behavior. I'm not seeing where POSIX-future (i.e., http://austingroupbugs.net/view.php?id=529 response 0001200 dated 2012-04-19 15:18) prohibits the GNU/Linux behavior. If there is such a prohibition, isn't that more likely to be a bug in POSIX-future than in GNU/Linux? ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:32 ` Paul Eggert @ 2016-12-05 16:39 ` Rich Felker 2016-12-05 17:17 ` Paul Eggert 0 siblings, 1 reply; 21+ messages in thread From: Rich Felker @ 2016-12-05 16:39 UTC (permalink / raw) To: Paul Eggert Cc: Michael Kerrisk, Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner On Mon, Dec 05, 2016 at 08:32:37AM -0800, Paul Eggert wrote: > On 12/05/2016 08:22 AM, Rich Felker wrote: > >POSIX-future does not permit the Linux behavior. > > I'm not seeing where POSIX-future (i.e., > http://austingroupbugs.net/view.php?id=529 response 0001200 dated > 2012-04-19 15:18) prohibits the GNU/Linux behavior. See the following text: ------------------------------------------------------------------------ At line 22871 [XSH close DESCRIPTION], change: If close( ) is interrupted by a signal that is to be caught, it shall return -1 with errno set to [EINTR] and the state of fildes is unspecified. If an I/O error occurred while reading from or writing to the file system during close( ), it may return -1 with errno set to [EIO]; if this error is returned, the state of fildes is unspecified. to: If close( ) is interrupted by a signal that is to be caught, then it is unspecified whether it returns -1 with errno set to [EINTR] with ^^^^^^^^^^^^^^^^^^^ fildes remaining open, or returns -1 with errno set to [EINPROGRESS] ^^^^^^^^^^^^^^^^^^^^^ with fildes being closed, or returns 0 to indicate successful completion; except that if POSIX_CLOSE_RESTART is defined as 0, then the option of returning -1 with errno set to [EINTR] and fildes remaining open shall not occur. If close() returns -1 with errno set to [EINTR], it is unspecified whether fildes can subsequently be passed to any function except close( ) or posix_close( ) without error. For all other error situations (except for [EBADF] where fildes was invalid), fildes shall be closed. If fildes was closed even though the close operation is incomplete, the close operation shall continue asynchronously and the process shall have no further ability to track the completion or final status of the close operation. ------------------------------------------------------------------------ If close returns -1 with errno set to EINTR, filedes must remain open (so that it is not subject to being re-assigned, in which case you have dangerous double-close races when looping on EINTR). > If there is such > a prohibition, isn't that more likely to be a bug in POSIX-future > than in GNU/Linux? No. This whole issue has been discussed to death and the bug is in Linux (not GNU/Linux, as it's in no way GNU's fault). Glibc is hopefully going to fix it on the userspace side; I have an open bug for it but it hasn't gotten a lot of attention: https://sourceware.org/bugzilla/show_bug.cgi?id=14627 Rich ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close 2016-12-05 16:39 ` Rich Felker @ 2016-12-05 17:17 ` Paul Eggert 0 siblings, 0 replies; 21+ messages in thread From: Paul Eggert @ 2016-12-05 17:17 UTC (permalink / raw) To: Rich Felker Cc: Michael Kerrisk, Ondřej Bílka, Mark Mentovai, libc-alpha, Daniel Wagner On 12/05/2016 08:38 AM, Rich Felker wrote: > Glibc is > hopefully going to fix it on the userspace side; I have an open bug > for it Ah, thanks for clarifying. I now see that I already worked around the problem in GNU Emacs but forgot about it afterwards. On platforms lacking posix_close, Emacs treats a close error with errno==EINTR as if the close had succeeded. Although this leaks a file descriptor on some non-Linux systems, the leak is unlikely and is better than closing a random victim. ^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2016-12-07 12:37 UTC | newest] Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-12-03 18:05 [PATCH] Manual should discourage mixing TEMP_FAILURE_RETRY and close Mark Mentovai 2013-12-04 0:16 ` Ondřej Bílka 2013-12-04 0:38 ` Rich Felker 2013-12-05 17:35 ` Mark Mentovai 2016-12-05 14:49 ` Michael Kerrisk 2016-12-05 16:11 ` Rich Felker 2016-12-05 16:18 ` Michael Kerrisk 2016-12-05 16:23 ` Rich Felker 2016-12-05 16:27 ` Michael Kerrisk 2016-12-05 16:34 ` Rich Felker 2016-12-05 16:41 ` Michael Kerrisk (man-pages) 2016-12-05 16:50 ` Rich Felker 2016-12-06 9:57 ` Michael Kerrisk (man-pages) 2016-12-06 15:52 ` Rich Felker 2016-12-06 22:43 ` Zack Weinberg 2016-12-06 23:58 ` Rich Felker 2016-12-07 12:16 ` Michael Kerrisk (man-pages) 2016-12-07 12:37 ` Michael Kerrisk (man-pages) 2016-12-05 16:32 ` Paul Eggert 2016-12-05 16:39 ` Rich Felker 2016-12-05 17:17 ` Paul Eggert
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 read-only IMAP folder(s) and NNTP newsgroup(s).