[4803] in testers

home help back first fref pref prev next nref lref last post

possibly-relevant fix to an ORBit bug

daemon@ATHENA.MIT.EDU (Larry Stone)
Fri Jun 15 00:09:20 2001

Date: Fri, 15 Jun 2001 0:09:14 EDT
From: Larry Stone <lcs@MIT.EDU>
Reply-To: <lcs@MIT.EDU>
To: testers@MIT.EDU
Message-ID: <CMM.0.90.4.992578154.lcs@defiant.mit.edu>

The patch below fixes a bug that affects ORBit (including the older version
in the Athena 9.0 source) on Solaris.  It fixes a misuse of writev(2)
that matters more on Solaris than Linux: although writev is not supposed
to handle arrays of more than IOV_MAX iovec's, IOV_MAX is 1024 on Linux so
they could get away with sloppy coding (i.e. just shoving a chain of iovecs
at writev without even counting).  Solaris, however, doesn't seem to return
the appropriate error (EINVAL) for too many iovecs, it just drops some 
bytes out of spite.  The result is that the recipient of a munged CORBA
rpc message will probably crash in the demarshaller after reading random
garbage as an array or string length.  

It was causing "reproducibly random" crashes in various Nautilus components
on Solaris which the patch has eliminated.  

Is there still any common case of GNOME apps failing this way on Athena,
esp. on the Solaris platform?  The key symptom would be a crash of something
that takes the "server" (i.e. callee) role in a CORBA transaction; this
can be an app that gets a callback as well as a "server" component.  If
the routine that crashes is named <mumble>_skel then it's a server CORBA
stub.  

If anyone can give me a reproducible case like this, I'll try this patch
(unless anyone else wants to try first).

	-- Larry

*** src/IIOP/giop-msg-buffer.c.orig	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;
  }

home help back first fref pref prev next nref lref last post