https://bugzilla.novell.com/show_bug.cgi?id=282196
matz@novell.com changed:
What |Removed |Added
----------------------------------------------------------------------------
AssignedTo|bnc-team- |pbaudis@novell.com
|screening@forge.provo.novell|
|.com |
Status|ASSIGNED |NEW
------- Comment #7 from matz@novell.com 2007-06-08 07:16 MST -------
Ah well, please tell that next time, I was testing in my homedir (NFS) ;)
Now I don't get EINVALs. It instead now works just fine in both cases,
with or without using the glibc wrapper. kernel is kernel-default-2.6.18.2-34.
Using your compile flags indeed does break it though in the glibc-wrapper
case indeed. It's the -D_GNU_SOURCE, which breaks it, because only
then the glibc wrapper is used at all. Without it SPLICE_F_MOVE will not
be defined and hence your own header will provide the splice() wrapper,
which I missed before. Okay, glibc indeed has a bug here.
The problem (I think) is in ./sysdeps/unix/sysv/linux/i386/sysdep.h,
in the (extremely seldomly used) DOARGS_6 macro. It's used only from
the syscall() function itself, and then for automatically generated
wrapper for 6 argument syscalls (of which splice() is one).
The problem here is these definitions:
#define DOARGS_4 _DOARGS_4 (24)
#define _PUSHARGS_4 pushl %esi; ...
..
#define DOARGS_5 _DOARGS_5 (32)
#define _PUSHARGS_5 pushl %edi; ...
..
#define DOARGS_6 _DOARGS_6 (36)
#define _PUSHARGS_6 pushl %ebp; ...
Note how the important number (used as offset from %esp) has a gap of
eight between the 4 and 5 argument case. This accounts for the step to
the next argument (given on the stack by the caller of functions using these
macros), plus the adjustment because we emit the "pushl %edi" before,
which changes %esp by four more. This is also the gap between DOARGS_3
and DOARGS_4. The exact same pattern happens in DOARGS_6 (it pushes
%ebp), but still the gap is only 4. This results in a shift of arguments
by exactly four bytes, or one argument overall, which can be seen quite
nicely in the strace:
splice(0x8048711, 0x3, 0, 0x1, 0, 0x68b);
the 0x8048711 actually is the return address. The fix should be easy:
substitute the faulty line by:
#define DOARGS_6 _DOARGS_6 (40)
...
Ohh, I just see that this was fixed in upstream glibc on 2006-10-11 by:
2006-10-11 Ulrich Drepper