Bug 146238 - readv( )/writev( ) can not run properly.
Summary: readv( )/writev( ) can not run properly.
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux 4
Classification: Red Hat
Component: kernel
Version: 4.0
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
: ---
Assignee: Stephen Tweedie
QA Contact: Brian Brock
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2005-01-26 10:03 UTC by L3support
Modified: 2018-10-19 19:04 UTC (History)
5 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2005-02-02 23:50:55 UTC
Target Upstream Version:
Embargoed:


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

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.


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