patch for writev bug in IIOP



The patch below fixes a bug in ORBit 0.5.8 that especially affects
Solaris.  giop_send_buffer_write was calling writev(2) without checking
the length of the iovec array.  Writev(2) cannot be expected to take
more than IOV_MAX iovecs at a time, but on Linux this is less of an
issue since IOV_MAX == 1024.  On Solaris 8, IOV_MAX == 16, so it is more
noticeable.  Even more unfortunately, Solaris doesn't seem to return the
expected error when the length is violated, it just drops some bytes on
the floor out of spite.  This results in a corrupted message that
usually makes the recipient crash in the demarshaller (e.g.  after
reading random garbage as the length of an array or string and wandering
off into deep space).

The change respects IOV_MAX, and cleans up the logic a bit.
I was seeing common crashes of Nautilus (1.0.3) view components such as
nautilus_history_view and nautilus_notes_view, in the
Nautilus_View_history_changed server stub (often the recipient of huge
RPC messages), and it's fixed those.

Can someone on this list accept this change into the ORBit source?

        -- Larry

*** src/IIOP/giop-msg-buffer.c     Sun May 13 03:05:52 2001
--- src/IIOP/giop-msg-buffer.c  Wed Jun 13 20:42:48 2001
***************
*** 172,245 ****
  gint
  giop_send_buffer_write(GIOPSendBuffer *send_buffer)
  {
!   gulong nvecs;
!   glong res, sum, t;
    struct iovec *curvec;
    int fd;
    GIOPConnection *cnx;
!   gint retval = -1;
  
    cnx = GIOP_MESSAGE_BUFFER(send_buffer)->connection;
    if(!cnx->is_valid)
      return -1;
  
    fd = GIOP_CONNECTION_GET_FD(cnx);
    nvecs = GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->len;
!   curvec = (struct iovec *)GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->data;
  
  #if defined(ORBIT_DEBUG) && 0
    g_print("Message of length %d looks like:\n",
          GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size);
!   for(sum = 0, t = 2; t < nvecs; t++) {
  
!     sum += curvec[t].iov_len;
      g_print("    [%p, %d]: %d\n", curvec[t].iov_base, curvec[t].iov_len,
!           sum);
    }
  #endif
-   res = writev(fd, curvec, nvecs);
  
!   sum = (GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size + sizeof(GIOPMessageHeader));
!   if(res < sum) {
!     if(res < 0) {
!       if(errno != EAGAIN) {
!       giop_main_handle_connection_exception(cnx);
!       goto out;
!       }
  
!       res = 0;
      }
  
!     /* wrote 7, iovecs 3, 2, 2, 4:
!        0 + 3 !> 7
!        3 + 2 !> 7
!        5 + 2 !> 7
!      */
  
!     for(t = 0; ; t += curvec->iov_len, curvec++, nvecs--) {
!       if((t + curvec->iov_len) > res)
        break;
      }
-     if((res - t) > 0) {
-       curvec->iov_len -= (res - t);
-       curvec->iov_base = (gpointer)((char *)curvec->iov_base + (res - t));
      }
  
!     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
!
!     t = writev(fd, curvec, nvecs);
!
!     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
!
!     if((t < 0) || ((res + t) < sum)) {
        giop_main_handle_connection_exception(cnx);
-       goto out;
-     }
-   }
-
-   retval = 0;
-
-  out:
  
    return retval;
  }
--- 172,253 ----
  gint
  giop_send_buffer_write(GIOPSendBuffer *send_buffer)
  {
!   gulong nvecs, newvi, nextvi, chunk;
!   glong written, msglen, total, gtotal = 0;
    struct iovec *curvec;
    int fd;
    GIOPConnection *cnx;
!   gint retval = 0;
!   gboolean blocking = FALSE;
  
    cnx = GIOP_MESSAGE_BUFFER(send_buffer)->connection;
    if(!cnx->is_valid)
      return -1;
  
+   /* make a private copy of iovec because we might mung base and len */
    fd = GIOP_CONNECTION_GET_FD(cnx);
    nvecs = GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->len;
!   curvec = alloca(sizeof(struct iovec) * nvecs);
!   memcpy(curvec, GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->data, sizeof(struct iovec) * nvecs);
  
  #if defined(ORBIT_DEBUG) && 0
    g_print("Message of length %d looks like:\n",
            GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size);
!   for(msglen = 0, t = 2; t < nvecs; t++) {
  
!     msglen += curvec[t].iov_len;
      g_print("    [%p, %d]: %d\n", curvec[t].iov_base, curvec[t].iov_len,
!             msglen);
    }
  #endif
  
!   msglen = GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size + sizeof(GIOPMessageHeader);
  
!   nextvi = 0;
!   while (nextvi < nvecs && retval == 0) {
!     chunk = MIN((nvecs - nextvi), IOV_MAX);
!     written = writev(fd, &curvec[nextvi], chunk);
!
!     if (written < 0) {
!       /* Switch to blocking mode and try again, easier than polling. */
!       if (!blocking && errno == EAGAIN) {
!         if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK) == -1)
!           /* Worth a warning because failure to set blocking will cause a spin */
!           g_warning("IIOP: fcntl(%d): %s", fd, strerror(errno));
!         else {
!           blocking = TRUE;
!           continue;
          }
  
!       /* Any other error, just give up. */
!       } else {
!         g_warning("IIOP:  writev(%d): %s", fd, strerror(errno));
!       }
!       retval =  -1;
  
!     /* compute next iovec to send */
!     } else {
!       gtotal += written;
!       if (gtotal >= msglen)
          break;
+       for (total = 0, newvi = nextvi;
+            newvi < nvecs && total + curvec[newvi].iov_len <= written;
+            total += curvec[newvi].iov_len, ++newvi)
+         /*EMPTY*/ ;
+       if (total < written) {
+         curvec[newvi].iov_len -= (written - total);
+         curvec[newvi].iov_base += (written - total);
+       }
+       if (newvi >= nvecs)
+         g_warning("IIOP: sanity check in giop_send_buffer_write: iovec index out of range.");
+       nextvi = newvi;
      }
    }
  
!   if (blocking)
!     (void)fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
!   if (retval < 0)
      giop_main_handle_connection_exception(cnx);
  
    return retval;
  }





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]