Bug 14627 - close() should set errno to EINPROGRESS when interrupted by a signal
Summary: close() should set errno to EINPROGRESS when interrupted by a signal
Status: NEW
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-09-26 04:32 IST by Rich Felker
Modified: 2016-10-28 08:05 IST (History)
4 users (show)

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


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rich Felker 2012-09-26 04:32:59 IST
Background: Historically, there has been a disagreement over the behavior of close() when interrupted by a signal. Some implementations (e.g. HPUX) had it leave the file descriptor open when returning with EINTR; others (Linux, AIX) closed it unconditionally, but returned with EINTR if a signal arrived while close() was interrupted before returning. This ambiguity was acceptable for single-threaded applications, which could just unconditionally call close() again on EINTR, possibly getting EBADF if the file descriptor no longer existed due to the Linux/AIX behavior. It's not acceptable for multi-threaded applications, where calling close again could close a file descriptor just obtained by another thread - which can have far-reaching and extremely dangerous consequences.

The issue was referred to the Austin Group for interpretation (as defect #529, http://austingroupbugs.net/view.php?id=529), and was resolved by:

1) Requiring the HPUX behavior, leaving the file descriptor open, if close() returns with EINTR.

2) Allowing implementations that do not want to offer this behavior to return with EINPROGRESS instead of EINTR to indicate that close() did not finish waiting for the file/device to finish closing, but that the file descriptor has been deallocated.

3) Defining a new posix_close() function with a flag to control the behavior.

Reportedly, the Linux kernel developers are vehemently opposed to changing the behavior of close/EINTR to match HPUX, so I think it's safe to say the behavior of the kernel will not change. Some links to discussions and information on their opinions can be found here:

https://news.ycombinator.com/item?id=3363819

For what it's worth, I agree with them that having close() return without having deallocated the file descriptor is a highly undesirable behavior. However, it's also wrong (and now non-conformant, with the final accepted text from Austin Group defect #529 applied to POSIX) to return with EINTR, an error code which means the side effects of the function did not take place, when the side effects did in fact take place.

Fortunately, the revised text in POSIX gives an easy-out that should make everybody happy: the option to return with EINPROGRESS.

Since the kernel developers seem to be uninterested in changing the kernel to return EINPROGRESS (and even if they did, it would not fix the issue on older kernels), I propose that glibc catch the EINTR error from close() on Linux and remap it to EINPROGRESS. If Linux ever catches up and starts returning EINPROGRESS directly, nothing will break. The only possible breakage would be if, at some point in the future, Linux starts returning EINTR with the real EINTR semantics (HPUX semantics), but I'm pretty sure this is not going to happen given the developers' attitudes on the matter.
Comment 1 Steven Stewart-Gallus 2015-01-02 00:41:36 IST
Some people check close for errors and exit the program if they occur. As much as it is hacky and ugly I think it'd be better to return 0 instead of EINPROGRESS.
Comment 2 Rich Felker 2015-01-02 02:31:20 IST
I tend to agree. EINPROGRESS is not useful to report, since the operation already succeeded, and it's potentially going to be misinterpreted, so I think returning success is preferable.
Comment 3 __vic 2016-10-28 08:05:47 IST
Second this! Why return EINTR if file is already closed? It is a success, not an error. The postcondition is satisfied. EINTR must be returned only if you want user repeated the call again.