[newlib-cygwin] Cygwin: AF_UNIX: fix accept behaviour
Corinna Vinschen
corinna@sourceware.org
Wed Mar 7 15:24:00 GMT 2018
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=855e5d7e144ac1e302087cf08c37eec13c62f75a
commit 855e5d7e144ac1e302087cf08c37eec13c62f75a
Author: Corinna Vinschen <corinna@vinschen.de>
Date: Wed Mar 7 16:23:44 2018 +0100
Cygwin: AF_UNIX: fix accept behaviour
* Use correct cygwait/WFSO invocation to not die on cancel and signals
uncontrolled.
* Manage io handles under io_lock.
* Copy peer address to user space under SEH to avoid a resource leak.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diff:
---
winsup/cygwin/fhandler_socket_unix.cc | 52 +++++++++++++++++++++++++----------
1 file changed, 37 insertions(+), 15 deletions(-)
diff --git a/winsup/cygwin/fhandler_socket_unix.cc b/winsup/cygwin/fhandler_socket_unix.cc
index dcd4938..6eca668 100644
--- a/winsup/cygwin/fhandler_socket_unix.cc
+++ b/winsup/cygwin/fhandler_socket_unix.cc
@@ -901,6 +901,7 @@ fhandler_socket_unix::listen_pipe ()
NTSTATUS status;
IO_STATUS_BLOCK io;
HANDLE evt = NULL;
+ DWORD waitret = WAIT_OBJECT_0;
io.Status = STATUS_PENDING;
if (!is_nonblocking () && !(evt = create_event ()))
@@ -909,12 +910,18 @@ fhandler_socket_unix::listen_pipe ()
FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
if (status == STATUS_PENDING)
{
- if (cygwait (evt ?: get_handle ()) == WAIT_OBJECT_0)
+ waitret = cygwait (evt ?: get_handle (), cw_infinite,
+ cw_cancel | cw_sig_eintr);
+ if (waitret == WAIT_OBJECT_0)
status = io.Status;
}
if (evt)
NtClose (evt);
- if (status == STATUS_PIPE_LISTENING)
+ if (waitret == WAIT_CANCELED)
+ pthread::static_cancel_self ();
+ else if (waitret == WAIT_SIGNALED)
+ set_errno (EINTR);
+ else if (status == STATUS_PIPE_LISTENING)
set_errno (EAGAIN);
else if (status != STATUS_PIPE_CONNECTED)
__seterrno_from_nt_status (status);
@@ -929,7 +936,9 @@ fhandler_socket_unix::disconnect_pipe (HANDLE ph)
status = NtFsControlFile (ph, NULL, NULL, NULL, &io, FSCTL_PIPE_DISCONNECT,
NULL, 0, NULL, 0);
- if (status == STATUS_PENDING && cygwait (ph) == WAIT_OBJECT_0)
+ /* Short-lived. Don't use cygwait. We don't want to be interrupted. */
+ if (status == STATUS_PENDING
+ && WaitForSingleObject (ph, INFINITE) == WAIT_OBJECT_0)
status = io.Status;
if (!NT_SUCCESS (status))
{
@@ -1290,13 +1299,17 @@ fhandler_socket_unix::accept4 (struct sockaddr *peer, int *len, int flags)
/* Our handle is now connected with a client. This handle is used
for the accepted socket. Our handle has to be replaced with a
new instance handle for the next accept. */
+ AcquireSRWLockExclusive (&io_lock);
HANDLE accepted = get_handle ();
HANDLE new_inst = create_pipe_instance ();
int error = ENOBUFS;
- if (new_inst)
+ if (!new_inst)
+ ReleaseSRWLockExclusive (&io_lock);
+ else
{
/* Set new io handle. */
set_io_handle (new_inst);
+ ReleaseSRWLockExclusive (&io_lock);
/* Prepare new file descriptor. */
cygheap_fdnew fd;
@@ -1323,21 +1336,30 @@ fhandler_socket_unix::accept4 (struct sockaddr *peer, int *len, int flags)
error = sock->recv_peer_name ();
if (error == 0)
{
- if (peer)
+ __try
{
- sun_name_t *sun = sock->get_peer_sun_path ();
- if (sun)
+ if (peer)
{
- memcpy (peer, &sun->un, MIN (*len, sun->un_len));
- *len = sun->un_len;
+ sun_name_t *sun = sock->get_peer_sun_path ();
+ if (sun)
+ {
+ memcpy (peer, &sun->un,
+ MIN (*len, sun->un_len));
+ *len = sun->un_len;
+ }
+ else if (len)
+ *len = 0;
}
- else if (len)
- *len = 0;
+ fd = sock;
+ if (fd <= 2)
+ set_std_handle (fd);
+ return fd;
+ }
+ __except (NO_ERROR)
+ {
+ error = EFAULT;
}
- fd = sock;
- if (fd <= 2)
- set_std_handle (fd);
- return fd;
+ __endtry
}
delete sock;
}
More information about the Cygwin-cvs
mailing list