Description of problem: If a C code is compiled with the -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 flag then the offset argument for pread() is passed as 0 or some garbage number. This happens only on a powerPC. The sample code to reproduce this is as follows: =================================================================== #include <fcntl.h> #include <stdio.h> #include <unistd.h> int main(void) { int fdin, fdout, ret; char *buf; off_t off=73728; buf=(char *) malloc(131072); if (!buf) {printf ("Bad"); exit(0);} fdin = open("/oradata/BAN25/system01.dbf", O_RDONLY); if(fdin<0) printf("fdin error\n"); fdout = open("/tmp/checksystem.dbf", O_WRONLY | O_CREAT); if(fdout<0) printf("fdout error\n"); ret = pread(fdin, buf, 8192, off); if(ret!=8192){printf("error read\n");} ret = write(fdout, buf, 8192); if(ret!=8192){printf("error write\n");} close(fdin); close(fdout); } =================================================================== and was compiled as follows #gcc -g -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 try.c The strace output for the same is attached with this bug (strace.out). strace was generated as: #strace -f ./a.out >strace.out 2>&1 Now pread would work fine if these changes were done. -> If pread() is changed to pread64() in teh code, then things work fine. -> also ifthe code is compiled with -D_XOPEN_SOURCE=500 and things worked fine but unfortunately I cannot use the -D_XOPEN_SOURCE=500 flag as this flag seems to uset the following type definations: uint, u_long etc, which are being used in the code base. The same code was compliled on an Intel and AMD system and pread() worked fine without the -D_XOPEN_SOURCE=500 compilation flag. That is the offset was passed sucessfully. Why does this happen? Version-Release number of selected component (if applicable): This fails on a powerpc with either of the gcc versions glibc-2.3.4-2.19 and glibc-2.3.4-2.25 How reproducible: Always reproducable (consistant) Steps to Reproduce: 1. Write a C code with the pread() call 2. Set the debug flag -D_FILE_OFFSET_BITS=64 for gcc and compile. 3. strace output for the execution shows that pread64()is called internally and the offset value is changed to some junk value or 0. I am passing the offset as 73728. Actual results: pread64(3, "\0\242\0\0\377\300\0\0\0\0\0\0\0\0\0\0\341\304\0\0\0\0"..., 8192, 0) Expected results: pread64(3, "\0\242\0\0\377\300\0\0\0\0\0\0\0\0\0\0\341\304\0\0\0\0"..., 8192, 73728) Additional info: If I directly call pread64() within the code, things work fine.
Created attachment 155458 [details] strace output for the code.
Please read info libc 'Feature Test Macros' and try to use -Wimplicit-function-declaration (part of -Wall) on your sources (and, unrelated, remember that when O_CREAT is used, 3rd argument to open is mandatory). pread and pread64 functions were added in SUSv3, therefore they are only available in the headers with -D_XOPEN_SOURCE=500, -D_XOPEN_SOURCE=600, or -D_GNU_SOURCE. When you don't have prototype of a function, in addition to e.g. miscompiling functions that return some other type than int, with -D_FILE_OFFSET_BITS=64 the non-*64 functions aren't redirected to their *64 counterparts either. So, in your testcase, the result is basically: int pread (); // implicit function declaration ... pread (fdin, buf, 8192, off); // int, void *, uint, long long arguments But, pread takes int, void *, uint, long arguments. On little endian 32-bit arch that means just using the bottom 32 bits of off, on big endian 32-bit arch usually the top 32 bits of off, but on ppc additionally long long values are passed only starting on odd registers, so int, void *, uint, long long is passed as int, void *, uint, pad, high 32 bits, low 32 bits.