[PATCH 1/3] libcsupport: Add and use rtems_libio_iovec_eval()

Sebastian Huber sebastian.huber at embedded-brains.de
Mon Dec 16 13:29:04 UTC 2013


Pass also zero-size buffers to the write handler since they may have
side-effects for non-regular files, e.g. sending of an empty message.
---
 cpukit/libcsupport/include/rtems/libio_.h |   56 ++++++++++++++++
 cpukit/libcsupport/src/readv.c            |   88 +++++---------------------
 cpukit/libcsupport/src/writev.c           |   98 +++++------------------------
 testsuites/psxtests/psxrdwrv/psxrdwrv.scn |    8 ++-
 testsuites/psxtests/psxrdwrv/test.c       |   47 +++++++++++---
 5 files changed, 129 insertions(+), 168 deletions(-)

diff --git a/cpukit/libcsupport/include/rtems/libio_.h b/cpukit/libcsupport/include/rtems/libio_.h
index 8856566..936c89d 100644
--- a/cpukit/libcsupport/include/rtems/libio_.h
+++ b/cpukit/libcsupport/include/rtems/libio_.h
@@ -21,7 +21,9 @@
 #ifndef _RTEMS_RTEMS_LIBIO__H
 #define _RTEMS_RTEMS_LIBIO__H
 
+#include <sys/uio.h>
 #include <errno.h>
+#include <limits.h>
 
 #include <rtems.h>
 #include <rtems/libio.h>
@@ -832,6 +834,60 @@ static inline bool rtems_filesystem_is_parent_directory(
   return tokenlen == 2 && token [0] == '.' && token [1] == '.';
 }
 
+static inline ssize_t rtems_libio_iovec_eval(
+  int fd,
+  const struct iovec *iov,
+  int iovcnt,
+  uint32_t flags,
+  rtems_libio_t **iopp
+)
+{
+  ssize_t        total;
+  int            v;
+  rtems_libio_t *iop;
+
+  rtems_libio_check_fd( fd );
+  iop = rtems_libio_iop( fd );
+  rtems_libio_check_is_open( iop );
+  rtems_libio_check_permissions_with_error( iop, flags, EBADF );
+
+  *iopp = iop;
+
+  /*
+   *  Argument validation on IO vector
+   */
+  if ( iov == NULL )
+    rtems_set_errno_and_return_minus_one( EINVAL );
+
+  if ( iovcnt < 0 )
+    rtems_set_errno_and_return_minus_one( EINVAL );
+
+  if ( iovcnt > IOV_MAX )
+    rtems_set_errno_and_return_minus_one( EINVAL );
+
+  /*
+   *  OpenGroup says that you are supposed to return EINVAL if the
+   *  sum of the iov_len values in the iov array would overflow a
+   *  ssize_t.
+   */
+  total = 0;
+  for ( v = 0 ; v < iovcnt ; v++ ) {
+    int len = iov[ v ].iov_len;
+
+    if ( len < 0 || len > SSIZE_MAX - total ) {
+      rtems_set_errno_and_return_minus_one( EINVAL );
+    }
+
+    total += len;
+
+    if ( iov[ v ].iov_base == NULL ) {
+      rtems_set_errno_and_return_minus_one( EINVAL );
+    }
+  }
+
+  return total;
+}
+
 /** @} */
 
 #ifdef __cplusplus
diff --git a/cpukit/libcsupport/src/readv.c b/cpukit/libcsupport/src/readv.c
index 2ff7f63..2400834 100644
--- a/cpukit/libcsupport/src/readv.c
+++ b/cpukit/libcsupport/src/readv.c
@@ -18,11 +18,9 @@
 #include "config.h"
 #endif
 
-#include <sys/types.h>
 #include <sys/uio.h>
 
 #include <rtems/libio_.h>
-#include <rtems/seterr.h>
 
 /**
  *  readv() - POSIX 1003.1 - Read a Vector
@@ -39,86 +37,30 @@ ssize_t readv(
 {
   ssize_t        total;
   int            v;
-  int            bytes;
   rtems_libio_t *iop;
-  bool           all_zeros;
 
-  rtems_libio_check_fd( fd );
-  iop = rtems_libio_iop( fd );
-  rtems_libio_check_is_open( iop );
-  rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_READ, EBADF );
-
-  /*
-   *  Argument validation on IO vector
-   */
-  if ( !iov )
-    rtems_set_errno_and_return_minus_one( EINVAL );
-
-  if ( iovcnt <= 0 )
-    rtems_set_errno_and_return_minus_one( EINVAL );
-
-  if ( iovcnt > IOV_MAX )
-    rtems_set_errno_and_return_minus_one( EINVAL );
-
-  /*
-   *  OpenGroup says that you are supposed to return EINVAL if the
-   *  sum of the iov_len values in the iov array would overflow a
-   *  ssize_t.
-   *
-   *  Also we would like to ensure that no IO is performed if there
-   *  are obvious errors in the iovec.  So this extra loop ensures
-   *  that we do not do anything if there is an argument error.
-   */
-
-  all_zeros = true;
-  for ( total=0, v=0 ; v < iovcnt ; v++ ) {
-    ssize_t old;
+  total = rtems_libio_iovec_eval( fd, iov, iovcnt, LIBIO_FLAGS_READ, &iop );
 
+  if ( total >= 0 ) {
     /*
-     *  iov[v].iov_len cannot be less than 0 because size_t is unsigned.
-     *  So we only check for zero.
+     *  Now process the readv().
      */
-    if ( iov[v].iov_base == 0 )
-      rtems_set_errno_and_return_minus_one( EINVAL );
+    total = 0;
+    for ( v = 0 ; v < iovcnt ; v++ ) {
+      ssize_t bytes = ( *iop->pathinfo.handlers->read_h )(
+        iop,
+        iov[ v ].iov_base,
+        iov[ v ].iov_len
+      );
 
-    /* check for wrap */
-    old    = total;
-    total += iov[v].iov_len;
-    if ( total < old )
-      rtems_set_errno_and_return_minus_one( EINVAL );
+      if ( bytes < 0 )
+        return -1;
 
-    if ( iov[v].iov_len )
-      all_zeros = false;
-  }
+      total += bytes;
 
-  /*
-   *  A readv with all zeros logically has no effect.  Even though
-   *  OpenGroup didn't address this case as they did with writev(),
-   *  we will handle it the same way for symmetry.
-   */
-  if ( all_zeros == true ) {
-    return 0;
-  }
-
-  /*
-   *  Now process the readv().
-   */
-  for ( total=0, v=0 ; v < iovcnt ; v++ ) {
-    bytes = (*iop->pathinfo.handlers->read_h)(
-      iop,
-      iov[v].iov_base,
-      iov[v].iov_len
-    );
-
-    if ( bytes < 0 )
-      return -1;
-
-    if ( bytes > 0 ) {
-      total       += bytes;
+      if ( bytes != iov[ v ].iov_len )
+        break;
     }
-
-    if (bytes != iov[ v ].iov_len)
-      break;
   }
 
   return total;
diff --git a/cpukit/libcsupport/src/writev.c b/cpukit/libcsupport/src/writev.c
index 47605a4..1c7caf1 100644
--- a/cpukit/libcsupport/src/writev.c
+++ b/cpukit/libcsupport/src/writev.c
@@ -1,5 +1,5 @@
 /*
- *  writev() - POSIX 1003.1 - Read a Vector
+ *  writev() - POSIX 1003.1 - Write a Vector
  *
  *  OpenGroup URL:
  *
@@ -17,11 +17,9 @@
 #include "config.h"
 #endif
 
-#include <sys/types.h>
 #include <sys/uio.h>
 
 #include <rtems/libio_.h>
-#include <rtems/seterr.h>
 
 ssize_t writev(
   int                 fd,
@@ -31,95 +29,31 @@ ssize_t writev(
 {
   ssize_t        total;
   int            v;
-  int            bytes;
   rtems_libio_t *iop;
-  ssize_t        old;
-  bool           all_zeros;
 
-  rtems_libio_check_fd( fd );
-  iop = rtems_libio_iop( fd );
-  rtems_libio_check_is_open( iop );
-  rtems_libio_check_permissions_with_error( iop, LIBIO_FLAGS_WRITE, EBADF );
-
-  /*
-   *  Argument validation on IO vector
-   */
-  if ( !iov )
-    rtems_set_errno_and_return_minus_one( EINVAL );
-
-  if ( iovcnt <= 0 )
-    rtems_set_errno_and_return_minus_one( EINVAL );
-
-  if ( iovcnt > IOV_MAX )
-    rtems_set_errno_and_return_minus_one( EINVAL );
-
-  /*
-   *  OpenGroup says that you are supposed to return EINVAL if the
-   *  sum of the iov_len values in the iov array would overflow a
-   *  ssize_t.
-   *
-   *  Also we would like to ensure that no IO is performed if there
-   *  are obvious errors in the iovec.  So this extra loop ensures
-   *  that we do not do anything if there is an argument error.
-   *
-   *  In addition,the OpenGroup specification says that if all the
-   *  iov_len entries are zero, then the call has no effect.  So
-   *  this loop does that check as well and sets "all-zero" appropriately.
-   *  The variable "all_zero" is used as an early exit point before
-   *  entering the write loop.
-   */
-  all_zeros = true;
-  for ( old=0, total=0, v=0 ; v < iovcnt ; v++ ) {
+  total = rtems_libio_iovec_eval( fd, iov, iovcnt, LIBIO_FLAGS_WRITE, &iop );
 
+  if ( total >= 0 ) {
     /*
-     *  iov[v].iov_len cannot be less than 0 because size_t is unsigned.
-     *  So we only check for zero.
+     *  Now process the writev().
      */
-    if ( iov[v].iov_base == 0 )
-      rtems_set_errno_and_return_minus_one( EINVAL );
-
-    if ( iov[v].iov_len )
-      all_zeros = false;
-
-    /* check for wrap */
-    old    = total;
-    total += iov[v].iov_len;
-    if ( total < old || total > SSIZE_MAX )
-      rtems_set_errno_and_return_minus_one( EINVAL );
-  }
-
-  /*
-   * A writev with all zeros is supposed to have no effect per OpenGroup.
-   */
-  if ( all_zeros == true ) {
-    return 0;
-  }
+    total = 0;
+    for ( v = 0 ; v < iovcnt ; v++ ) {
+      ssize_t bytes = ( *iop->pathinfo.handlers->write_h )(
+        iop,
+        iov[ v ].iov_base,
+        iov[ v ].iov_len
+      );
 
-  /*
-   *  Now process the writev().
-   */
-  for ( total=0, v=0 ; v < iovcnt ; v++ ) {
-    /* all zero lengths has no effect */
-    if ( iov[v].iov_len == 0 )
-      continue;
+      if ( bytes < 0 )
+        return -1;
 
-    bytes = (*iop->pathinfo.handlers->write_h)(
-      iop,
-      iov[v].iov_base,
-      iov[v].iov_len
-    );
+      total += bytes;
 
-    if ( bytes < 0 )
-      return -1;
-
-    if ( bytes > 0 ) {
-      total       += bytes;
+      if ( bytes != iov[ v ].iov_len )
+        break;
     }
-
-    if (bytes != iov[ v ].iov_len)
-      break;
   }
 
   return total;
 }
-
diff --git a/testsuites/psxtests/psxrdwrv/psxrdwrv.scn b/testsuites/psxtests/psxrdwrv/psxrdwrv.scn
index 26e1ea5..7d070ea 100644
--- a/testsuites/psxtests/psxrdwrv/psxrdwrv.scn
+++ b/testsuites/psxtests/psxrdwrv/psxrdwrv.scn
@@ -3,16 +3,20 @@ writev bad file descriptor -- EBADF
 readv bad file descriptor -- EBADF
 writev bad iovec pointer -- EINVAL
 readv bad iovec pointer -- EINVAL
-readv bad iovcnt of 0 -- EINVAL
+writev bad iovcnt of 0 -- EINVAL
 readv bad iovcnt of 0 -- EINVAL
 writev bad iovcnt negative -- EINVAL
 readv bad iovcnt negative -- EINVAL
 writev bad iov[i].iov_base -- EINVAL
 readv bad iov[i].iov_base -- EINVAL
 writev bad iov[i].iov_len < 0 -- EINVAL
-readv bad iov[i].iov_len = 0 -- EINVAL
+readv bad iov[i].iov_len < 0 -- EINVAL
 writev iov_len total overflows -- EINVAL
 readv iov_len total overflows -- EINVAL
+writev iov_len works with no effect -- OK
+readv iov_len works with no effect -- OK
+readv bad iovcnt of IOV_MAX + 1 -- EINVAL
+writev bad iovcnt of IOV_MAX + 1 -- EINVAL
 File written using writev .. OK
 File read using readv .. OK
 *** END OF TEST PSXRDWRV ***
diff --git a/testsuites/psxtests/psxrdwrv/test.c b/testsuites/psxtests/psxrdwrv/test.c
index cedca90..cb425db 100644
--- a/testsuites/psxtests/psxrdwrv/test.c
+++ b/testsuites/psxtests/psxrdwrv/test.c
@@ -27,6 +27,7 @@
 #include <utime.h>
 #include <string.h>
 #include <inttypes.h>
+#include <limits.h>
 
 #include <stdio.h>
 #include <unistd.h>
@@ -217,6 +218,7 @@ int doErrorTest(void)
   }
   fd = fileno(fp);
 
+#ifdef __rtems__
   /* writev --  bad iovec pointer */
   puts("writev bad iovec pointer -- EINVAL");
   rc = writev(fd, NULL, 4);
@@ -234,11 +236,12 @@ int doErrorTest(void)
     fclose(fp);
     return FALSE;
   }
+#endif /* __rtems__ */
 
   /* writev --  bad iovcnt 0 */
-  puts("readv bad iovcnt of 0 -- EINVAL");
+  puts("writev bad iovcnt of 0 -- EINVAL");
   rc = writev(fd, vec, 0);
-  if ( (rc != -1) || (errno != EINVAL) ) {
+  if ( rc != 0 ) {
     printf( "writev error 3: %d=%s\n", errno, strerror(errno) );
     fclose(fp);
     return FALSE;
@@ -247,7 +250,7 @@ int doErrorTest(void)
   /* readv --  bad iovcnt 0 */
   puts("readv bad iovcnt of 0 -- EINVAL");
   rc = readv(fd, vec, 0);
-  if ( (rc != -1) || (errno != EINVAL) ) {
+  if ( rc != 0 ) {
     printf( "readv error 3: %d=%s\n", errno, strerror(errno) );
     fclose(fp);
     return FALSE;
@@ -271,6 +274,7 @@ int doErrorTest(void)
     return FALSE;
   }
 
+#ifdef __rtems__
   /* writev --  bad iov[i].iov_base */
   vec[0].iov_base = vec;
   vec[0].iov_len = 100;
@@ -296,6 +300,7 @@ int doErrorTest(void)
     fclose(fp);
     return FALSE;
   }
+#endif /* __rtems__ */
 
   /*  writev --  bad iov[i].iov_len < 0 */
   vec[0].iov_base = vec;
@@ -310,12 +315,12 @@ int doErrorTest(void)
     return FALSE;
   }
 
-  /*  readv --  bad iov[i].iov_len = 0 */
+  /*  readv --  bad iov[i].iov_len < 0 */
   vec[0].iov_base = vec;
   vec[0].iov_len = 100;
   vec[1].iov_base = vec;
   vec[1].iov_len = -1024;
-  puts("readv bad iov[i].iov_len = 0 -- EINVAL");
+  puts("readv bad iov[i].iov_len < 0 -- EINVAL");
   rc = readv(fd, vec, 2);
   if ( (rc != -1) || (errno != EINVAL) ) {
     printf( "readv error 6: %d=%s\n", errno, strerror(errno) );
@@ -325,11 +330,11 @@ int doErrorTest(void)
 
   /*  writev --  iov_len total overflows */
   vec[0].iov_base = vec;
-  vec[0].iov_len = SIZE_MAX;
+  vec[0].iov_len = INT_MAX;
   vec[1].iov_base = vec;
-  vec[1].iov_len = SIZE_MAX;
+  vec[1].iov_len = INT_MAX;
   vec[2].iov_base = vec;
-  vec[2].iov_len = SIZE_MAX;
+  vec[2].iov_len = INT_MAX;
   puts("writev iov_len total overflows -- EINVAL");
   rc = writev(fd, vec, 3);
   if ( (rc != -1) || (errno != EINVAL) ) {
@@ -340,11 +345,13 @@ int doErrorTest(void)
 
   /*  readv --  iov_len total overflows */
   vec[0].iov_base = vec;
-  vec[0].iov_len = SIZE_MAX;
+  vec[0].iov_len = INT_MAX;
   vec[1].iov_base = vec;
-  vec[1].iov_len = SIZE_MAX;
+  vec[1].iov_len = INT_MAX;
+  vec[2].iov_base = vec;
+  vec[2].iov_len = INT_MAX;
   puts("readv iov_len total overflows -- EINVAL");
-  rc = readv(fd, vec, 2);
+  rc = readv(fd, vec, 3);
   if ( (rc != -1) || (errno != EINVAL) ) {
     printf( "read error 7: rc=%d %d=%s\n", rc, errno, strerror(errno) );
     fclose(fp);
@@ -377,6 +384,24 @@ int doErrorTest(void)
     return FALSE;
   }
 
+#ifdef __rtems__
+  puts("readv bad iovcnt of IOV_MAX + 1 -- EINVAL");
+  rc = readv(fd, vec, IOV_MAX + 1);
+  if ( (rc != -1) || (errno != EINVAL) ) {
+    printf( "readv error 9: %d=%s\n", errno, strerror(errno) );
+    fclose(fp);
+    return FALSE;
+  }
+
+  puts("writev bad iovcnt of IOV_MAX + 1 -- EINVAL");
+  rc = writev(fd, vec, IOV_MAX + 1);
+  if ( (rc != -1) || (errno != EINVAL) ) {
+    printf( "writev error 9: %d=%s\n", errno, strerror(errno) );
+    fclose(fp);
+    return FALSE;
+  }
+#endif /* __rtems__ */
+
   fclose(fp);
   return TRUE;
 }
-- 
1.7.7




More information about the devel mailing list