Procházet zdrojové kódy

[Pal/{Linux,FreeBSD}] Force _DkReceiveHandle() to return PAL_ERROR_TRYAGAIN on interrupt

Previously, if an interrupt happened during recvmsg() syscall while
receiving object handles on parent-child socket, syscall was interrupted,
the handle was only partially initialized, but Pal ignored this error.
This commit forces _DkReceiveHandle() to return PAL_ERROR_TRYAGAIN in
case of such an interrupt (or return PAL_ERROR_DENIED on "impossible"
case of receiving a partial header).
Isaku Yamahata před 5 roky
rodič
revize
58bc2a7813
2 změnil soubory, kde provedl 38 přidání a 11 odebrání
  1. 19 5
      Pal/src/host/FreeBSD/db_streams.c
  2. 19 6
      Pal/src/host/Linux/db_streams.c

+ 19 - 5
Pal/src/host/FreeBSD/db_streams.c

@@ -384,12 +384,26 @@ int _DkReceiveHandle(PAL_HANDLE hdl, PAL_HANDLE * cargo)
     hdr.msg_flags = 0;
 
     int ret = INLINE_SYSCALL(recvmsg, 3, ch, &hdr, 0);
-    if (IS_ERR(ret) || ret < sizeof(struct hdl_header)) {
-        if (!IS_ERR(ret))
+    if (IS_ERR(ret))
+        return unix_to_pal_error(ERRNO(ret));
+    if (ret < sizeof(struct hdl_header)) {
+        /*
+         * This code block is just in case to cover all the possibilities.
+         * We know that the file descriptor is an unix domain socket with
+         * blocking mode and that the sender, _DkSendHandle() above, sends the
+         * header with single sendmsg syscall which transfers message atomically.
+         *
+         * read size == 0: return error for the caller to try again.
+         *                 It should result in EINTR.
+         *
+         * read size > 0: return error for the caller to give up this file
+         *                descriptor.
+         *                If the header can't be send atomically for some
+         *                reason, the sender should get EMSGSIZE.
+         */
+        if (!ret)
             return -PAL_ERROR_TRYAGAIN;
-
-        if (ERRNO(ret) != EINTR && ERRNO(ret) != ERESTART)
-            return -ERRNO(ret);
+        return -PAL_ERROR_DENIED;
     }
 
     // initialize variables to get body

+ 19 - 6
Pal/src/host/Linux/db_streams.c

@@ -392,13 +392,26 @@ int _DkReceiveHandle(PAL_HANDLE hdl, PAL_HANDLE * cargo)
     hdr.msg_flags = 0;
 
     int ret = INLINE_SYSCALL(recvmsg, 3, ch, &hdr, 0);
-
-    if (IS_ERR(ret) || (size_t)ret < sizeof(struct hdl_header)) {
-        if (!IS_ERR(ret))
+    if (IS_ERR(ret))
+        return unix_to_pal_error(ERRNO(ret));
+    if ((size_t)ret < sizeof(struct hdl_header)) {
+        /*
+         * This code block is just in case to cover all the possibilities.
+         * We know that the file descriptor is an unix domain socket with
+         * blocking mode and that the sender, _DkSendHandle() above, sends the
+         * header with single sendmsg syscall which transfers message atomically.
+         *
+         * read size == 0: return error for the caller to try again.
+         *                 It should result in EINTR.
+         *
+         * read size > 0: return error for the caller to give up this file
+         *                descriptor.
+         *                If the header can't be send atomically for some
+         *                reason, the sender should get EMSGSIZE.
+         */
+        if (!ret)
             return -PAL_ERROR_TRYAGAIN;
-
-        if (ERRNO(ret) != EINTR && ERRNO(ret) != ERESTART)
-            return -ERRNO(ret);
+        return -PAL_ERROR_DENIED;
     }
 
     // initialize variables to get body