Bug 146238

Summary: readv( )/writev( ) can not run properly.
Product: Red Hat Enterprise Linux 4 Reporter: L3support <linux-sid>
Component: kernelAssignee: Stephen Tweedie <sct>
Status: CLOSED NOTABUG QA Contact: Brian Brock <bbrock>
Severity: medium Docs Contact:
Priority: medium    
Version: 4.0CC: davej, halligan, jbaron, jturner, tao
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2005-02-02 23:50:55 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---
Attachments:
Description Flags
this is strace log none

Description L3support 2005-01-26 10:03:54 UTC
Description of problem:

readv()/writev() does not return -1,
although the vector count is zero.

Moreover, errno is not set appropriately.

manual says
-----------------------------------
RETURN VALUE
       On  success, the readv() function returns the number of bytes
read; the
       writev() function returns the number of bytes written.  On
error, -1 is
       returned, and errno is set appropriately.

ERRORS
       The  errors  are  as  given for read(2) and write(2). 
Additionally the
       following error is defined.

       EINVAL The sum of the iov_len values overflows an  ssize_t 
value.  Or,
              the vector count count is zero or greater than MAX_IOVEC.
-----------------------------------

If readv()/writev() is bug, we wish you modify it. 

Version-Release number of selected component (if applicable):


How reproducible:
always

Steps to Reproduce:
1.do program called readv()/writev().
  (set vector count is zero)
2.
3.
  
Actual results:
return value is zero, errno is zero.

Expected results:
return value is -1, errno is 22(EINVAL).

Additional info:

$ cat test_vio_0.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

main()
{
    int s;
    struct iovec w_vector[10];
    struct iovec r_vector[10];
    char buf[100];
    int i;

    /* now build up a two part writev and write it out */
    for( i = 0; i < sizeof( buf ); ++i ) {
        buf[i] = 'x';
    }
    for( i = 0; i < 10; ++i ) {
        w_vector[i].iov_base = buf;
        w_vector[i].iov_len = sizeof(buf);
    }
    for( i = 0; i < 10; ++i ) {
        r_vector[i].iov_base = buf;
        r_vector[i].iov_len = sizeof(buf);
    }
-----------------------------------
$ gcc test_vio_0.c
$ ./a.out
i=0, errno=0:Success
i=0, errno=0:Success
-----------------------------------
$ strace ./a.out > straVec.log 2>&1
$ cat straVec.log
execve("./a.out", ["./a.out"], [/* 24 vars */]) = 0
uname({sys="Linux", node="ipf13", ...}) = 0
brk(0)                                  = 0x6000000000004000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or
directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=111244, ...}) = 0
mmap(NULL, 111244, PROT_READ, MAP_PRIVATE, 3, 0) = 0x2000000000044000
close(3)                                = 0
open("/lib/tls/libc.so.6.1", O_RDONLY)  = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0002\0\1\0\0\0\200\226"...,
640) = 640
fstat(3, {st_mode=S_IFREG|0755, st_size=2747008, ...}) = 0
mmap(NULL, 2488936, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3,
0) = 0x2000000000060000
mprotect(0x20000000002a8000, 96872, PROT_NONE) = 0
mmap(0x20000000002b0000, 49152, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x240000) = 0x20000000002b0000
mmap(0x20000000002bc000, 14952, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x20000000002bc000
close(3)                                = 0
mmap(NULL, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x20000000002c0000
mmap(NULL, 32768, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x20000000002c4000
munmap(0x2000000000044000, 111244)      = 0
open("tmp.test_writev", O_RDWR|O_CREAT|O_TRUNC, 0777) = 3
writev(3, [], 0)                        = 0
fstat(1, {st_mode=S_IFREG|0664, st_size=1417, ...}) = 0
mmap(NULL, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0x2000000000044000
lseek(3, 0, SEEK_SET)                   = 0
readv(3, [], 0)                         = 0
close(3)                                = 0
write(1, "i=0, errno=0:Success\ni=0, errno="..., 42i=0, errno=0:Success
i=0, errno=0:Success
) = 42
munmap(0x2000000000044000, 65536)       = 0
exit_group(0)                           = ?

Comment 1 Jay Turner 2005-01-27 10:12:33 UTC
Looks like the tail end of the example code got chopped off.  Can you please
repost the same code as an attachment?

Comment 3 L3support 2005-02-01 06:48:09 UTC
Created attachment 110487 [details]
this is strace log

Comment 4 L3support 2005-02-01 07:01:04 UTC
Sorry, I have misunderstand on this completely.

Since the example code is short, we post it.
-----------------------------------------------
#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

main()
{
    int s;
    struct iovec w_vector[10];
    struct iovec r_vector[10];
    char buf[100];
    int i;

    /* now build up a two part writev and write it out */
    for( i = 0; i < sizeof( buf ); ++i ) {
        buf[i] = 'x';
    }
    for( i = 0; i < 10; ++i ) {
        w_vector[i].iov_base = buf;
        w_vector[i].iov_len = sizeof(buf);
    }
    for( i = 0; i < 10; ++i ) {
        r_vector[i].iov_base = buf;
        r_vector[i].iov_len = sizeof(buf);
    }

    /* testing writev() */
    s = open( "tmp.test_writev",O_RDWR|O_CREAT|O_TRUNC ,0777 );
    i = writev( s, &w_vector[0], 0 );
    fprintf( stdout, "i=%d, errno=%d:%s\n", i, errno, strerror(errno) );
    /* rewind, and test readv() */
    lseek( s, 0, SEEK_SET );
    i = readv( s, &r_vector[0], 0 );
    fprintf( stdout, "i=%d, errno=%d:%s\n", i, errno, strerror(errno) );
    close( s );
}
-----------------------------------------------

Comment 5 Stephen Tweedie 2005-02-02 23:50:55 UTC
This is not a bug.

As mentioned in the kernel source for this function:

	/*
	 * SuS says "The readv() function *may* fail if the iovcnt argument
	 * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
	 * traditionally returned zero for zero segments, so...
	 */
	ret = 0;
	if (nr_segs == 0)
		goto out;

And indeed, SUSv3 does have exactly that wording; the function is not required
to fail on count==0.

It's not even clear that the man page needs to be changed --- the above code is
from the common vfs layer's readv code, but individual filesystems have the
right to intercept readv calls and provide their own implementation.  So
3rd-party modules, for example, might well provide implementations which fail
with EINVAL on count==0.

Using the word "may" to show this in the man page might make sense, but the
kernel code does not need to be changed.