Bug 241370 - pread() always sets the offset=0 if gcc option -D_FILE_OFFSET_BITS=64 is set
pread() always sets the offset=0 if gcc option -D_FILE_OFFSET_BITS=64 is set
Status: CLOSED NOTABUG
Product: Red Hat Enterprise Linux 4
Classification: Red Hat
Component: glibc (Show other bugs)
4.3
powerpc Linux
medium Severity medium
: ---
: ---
Assigned To: Jakub Jelinek
Brian Brock
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2007-05-25 10:53 EDT by Vinod Sairaman
Modified: 2007-11-16 20:14 EST (History)
0 users

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2007-05-28 03:43:45 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)
strace output for the code. (1.86 KB, text/plain)
2007-05-25 10:53 EDT, Vinod Sairaman
no flags Details

  None (edit)
Description Vinod Sairaman 2007-05-25 10:53:12 EDT
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.
Comment 1 Vinod Sairaman 2007-05-25 10:53:12 EDT
Created attachment 155458 [details]
strace output for the code.
Comment 2 Jakub Jelinek 2007-05-28 03:43:45 EDT
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.

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