Bug 146238 - readv( )/writev( ) can not run properly.
readv( )/writev( ) can not run properly.
Status: CLOSED NOTABUG
Product: Red Hat Enterprise Linux 4
Classification: Red Hat
Component: kernel (Show other bugs)
4.0
All Linux
medium Severity medium
: ---
: ---
Assigned To: Stephen Tweedie
Brian Brock
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2005-01-26 05:03 EST by L3support
Modified: 2010-10-21 22:46 EDT (History)
5 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2005-02-02 18:50:55 EST
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:


Attachments (Terms of Use)
this is strace log (1.83 KB, text/plain)
2005-02-01 01:48 EST, L3support
no flags Details

  None (edit)
Description L3support 2005-01-26 05:03:54 EST
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 05:12:33 EST
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 01:48:09 EST
Created attachment 110487 [details]
this is strace log
Comment 4 L3support 2005-02-01 02:01:04 EST
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 18:50:55 EST
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.

Note You need to log in before you can comment on or make changes to this bug.