summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-08-07 00:05:01 -0400
committerRich Felker <dalias@aerifal.cx>2011-08-07 00:05:01 -0400
commit188ebf51b4ef58aa0ce0a3a09ed1756d6db2e2dd (patch)
treeb844ab40d69e87cb340eba3efb94f882046b17b4
parent8426a99048261b998a27557cf34f81626ffe9f12 (diff)
downloadmusl-188ebf51b4ef58aa0ce0a3a09ed1756d6db2e2dd.tar.gz
close should not be cancellable after "failing" with EINTR
normally we allow cancellation to be acted upon when a syscall fails with EINTR, since there is no useful status to report to the caller in this case, and the signal that caused the interruption was almost surely the cancellation request, anyway. however, unlike all other syscalls, close has actually performed its resource-deallocation function whenever it returns, even when it returned an error. if we allow cancellation at this point, the caller has no way of informing the program that the file descriptor was closed, and the program may later try to close the file descriptor again, possibly closing a different, newly-opened file. the workaround looks ugly (special-casing one syscall), but it's actually the case that close is the one and only syscall (at least among cancellation points) with this ugly property.
-rw-r--r--src/thread/cancel_impl.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/src/thread/cancel_impl.c b/src/thread/cancel_impl.c
index 4f78a63a..01f52b82 100644
--- a/src/thread/cancel_impl.c
+++ b/src/thread/cancel_impl.c
@@ -27,7 +27,8 @@ long (__syscall_cp)(long nr, long u, long v, long w, long x, long y, long z)
r = __syscall_cp_asm(&self->cp_sp, nr, u, v, w, x, y, z);
self->cp_ip = old_ip;
self->cp_sp = old_sp;
- if (r == -EINTR && self->cancel && !self->canceldisable) __cancel();
+ if (r==-EINTR && nr!=SYS_close && self->cancel && !self->canceldisable)
+ __cancel();
return r;
}