From kobayasi@nextech.co.jp  Mon Oct 12 02:04:48 1998
Received: from athena.nextech.co.jp (node163.nextech.co.jp [210.162.96.163])
          by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id CAA28290
          for <FreeBSD-gnats-submit@freebsd.org>; Mon, 12 Oct 1998 02:04:45 -0700 (PDT)
          (envelope-from kobayasi@nextech.co.jp)
Received: (from kobayasi@localhost)
	by athena.nextech.co.jp (8.8.8/3.6W) id SAA17994;
	Mon, 12 Oct 1998 18:04:22 +0900 (JST)
Message-Id: <199810120904.SAA17994@athena.nextech.co.jp>
Date: Mon, 12 Oct 1998 18:04:22 +0900 (JST)
From: Satosi KOBAYASI <kobayasi@north.ad.jp>
Reply-To: kobayasi@north.ad.jp
To: FreeBSD-gnats-submit@freebsd.org
Subject: writev() in libc_r causes loop
X-Send-Pr-Version: 3.2

>Number:         8281
>Category:       bin
>Synopsis:       writev() in libc_r causes loop
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Oct 12 02:10:00 PDT 1998
>Closed-Date:    Thu Dec 16 14:35:53 PST 1999
>Last-Modified:  Thu Dec 16 14:36:56 PST 1999
>Originator:     Satosi KOBAYASI
>Release:        FreeBSD 2.2.7-RELEASE i386
>Organization:
NORTH (Network Organization for Research and Technology in Hokkaido)
>Environment:

FreeBSD athena 2.2.7-RELEASE FreeBSD 2.2.7-RELEASE #0: Sun Oct  4 17:27:30 JST 1998     kobayasi@athena:/usr/local/src/remote/sys/compile/ASIX  i386

>Description:

writev() in libc_r causes loop when it's called with the following
arguments:
	* the iovcnt is more than 0
	* at the last member of the iovec array, the iov_len set to 0

(Detail)

writev() defined in /usr/src/lib/libc_r/uthread/uthread_writev.c, calls
_thread_sys_writev() in itself.

When _thread_sys_writev() returns 0, writev() does't increment the index 
of the iovec array. So if the index points to the last member of the 
array, writev() calls _thread_sys_writev() with the member whose iov_len
set to 0. Because there is nothing to write, _thread_sys_writev() returns
0, and writev() doesn't increment the index...

>How-To-Repeat:

Compile the following code with -lc_r, and run it.

#include <stdio.h>
#include <string.h>

#include <fcntl.h>
#include <sys/stat.h>

#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

static char	b1[] = "test";
static char	b2[] = "foo";

int main(int argc, char **argv)
{
  int	fd;
  struct iovec	buf[2];

  if (argc != 2) {
    fprintf(stderr, "Usage: %s <filename>\n", *argv);
    exit(1);
  }
  
  if ((fd = open(*(argv + 1), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
    perror("open");
    exit(1);
  }

  buf[0].iov_base = b1;
  buf[0].iov_len = strlen(b1);
  
  buf[1].iov_base = b2;
  buf[1].iov_len = 0;

  if (writev(fd, buf, 2) < 0) {
    perror("writev");
    exit(1);
  }
  
  close(fd);
  
  exit(0);
}

    
>Fix:

Apply the following patch or something like this.


--- uthread_writev.c.orig	Mon Oct 12 17:38:58 1998
+++ uthread_writev.c	Mon Oct 12 18:00:02 1998
@@ -83,6 +83,16 @@
 			/* Perform a non-blocking write syscall: */
 			n = _thread_sys_writev(fd, &p_iov[idx], iovcnt - idx);
 
+			/* To avoid loop */
+			if (n == 0) { 
+				while (idx < iovcnt && p_iov[idx].iov_len == 0)
+					idx++;
+				if (idx == iovcnt) {
+					ret = num;
+					break;
+				}
+			}
+			
 			/* Check if one or more bytes were written: */
 			if (n > 0) {
 				/*
>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->closed 
State-Changed-By: jasone 
State-Changed-When: Thu Dec 16 14:35:53 PST 1999 
State-Changed-Why:  
The provided fix was applied (with minor modifications). 
>Unformatted:
