Arguments offset and len in fallocate system call in Linux kernel have 64-bit types. However these arguments in fallocate wrapper in uClibc may have 32-bit types. In this case it's necessary to pass two 32-bit words to the systemc call for every argument - an actual argument and its sign extension.
Thus high word of 64-bit value must be 0 or 0xFFFFFFFF depending on sign of the original 32-bit value (offset or len). It is how sign extansion works - all high bits of the negative value must be 1. fallocate does sign extension incorrectly when 32 bit values are passed (offset or len). It just fills the second word of 64-bit value by zeros. E.g. fallocate works incorrectly when offset or length is negative value - in this case kernel thinks that positive values are passed. Signed-off-by: Yuriy Kolerov <[email protected]> --- libc/sysdeps/linux/common/fallocate.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libc/sysdeps/linux/common/fallocate.c b/libc/sysdeps/linux/common/fallocate.c index b2309e9..446d9ef 100644 --- a/libc/sysdeps/linux/common/fallocate.c +++ b/libc/sysdeps/linux/common/fallocate.c @@ -21,14 +21,12 @@ int attribute_hidden __libc_fallocate(int fd, int mode, __off_t offset, __off_t int ret; # if __WORDSIZE == 32 - uint32_t off_low = offset; - uint32_t len_low = len; - /* may assert that these >>31 are 0 */ - uint32_t zero = 0; + int32_t offset_sign_extension = (offset < 0) ? 0xFFFFFFFF : 0; + int32_t len_sign_extension = (len < 0) ? 0xFFFFFFFF : 0; INTERNAL_SYSCALL_DECL(err); ret = (int) (INTERNAL_SYSCALL(fallocate, err, 6, fd, mode, - __LONG_LONG_PAIR (zero, off_low), - __LONG_LONG_PAIR (zero, len_low))); + __LONG_LONG_PAIR (offset_sign_extension, offset), + __LONG_LONG_PAIR (len_sign_extension, len))); # elif __WORDSIZE == 64 INTERNAL_SYSCALL_DECL(err); ret = (int) (INTERNAL_SYSCALL(fallocate, err, 4, fd, mode, offset, len)); -- 2.2.0 _______________________________________________ uClibc mailing list [email protected] http://lists.busybox.net/mailman/listinfo/uclibc
