Bug 21761

Summary: write system call does not recognize prior fseek
Product: [Retired] Red Hat Linux Reporter: Karl D. Paxton <karl.paxton>
Component: libcAssignee: Jakub Jelinek <jakub>
Status: CLOSED NOTABUG QA Contact:
Severity: high Docs Contact:
Priority: medium    
Version: 6.2CC: dr, drepper
Target Milestone: ---   
Target Release: ---   
Hardware: i686   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2000-12-06 00:32:56 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Karl D. Paxton 2000-12-05 19:26:59 UTC
On a file opened for read & write (r+ or w+), a write() system call does 
not honor a prior fseek(), but writes its data at the file position that 
was in effect before the fseek().

Problem found in Linux 6.2 (Zoot), kernel 2.2.14-6.1.1smp, duplicated in 
Linux 7.0 (Guinness), kernel 2.2.16-22.

I have a small test program which demonstrates the problem nicely.  Can 
send it via e-mail or ftp if you wish.  The gist of it is:

    fwrite() 20 integers.
    fseek() back into the middle of that.
    write() another integer.

The value put out by the final write() should appear in the middle of the 
data file when the program is done.  In fact, it gets put at the end of
the file.

I ran this program on HP-UX and AIX to verify that Linux's behavior is 
indeed different from "standard" UNIX.

There is a work-around, but I called the severity "high" because a data 
file can be corrupted by this problem.

Comment 1 Jakub Jelinek 2000-12-06 09:51:22 UTC
If you mean test like:
#include <stdio.h>
#include <unistd.h>

int main()
{
  FILE *f = fopen ("/tmp/xxx", "w+");
  int i;

  for (i = 0; i < 20; i++)
    fwrite ("244", 3, 1, f);
  fseek (f, 15, SEEK_SET);
  write (fileno (f), "355", 3);
  fclose (f);
}
then there is really no guarantee that fseek will move the underlying file
descriptor position.
See http://www.opennc.org/onlinepubs/007908799/xsh/fseek.html
where it explicitely states that:
If the most recent operation, other than ftell(), on a given stream is
fflush(), the file offset in the underlying open file description will be
adjusted to reflect the location specified by fseek().

There is nothing about underlying file descriptor unless you call fflush
before it. And indeed, if I add fflush (f) in the above example either right
before the fseek or right after the fseek, 355 will be present at offset 15
(otherwise it can wind up at offset 60).

So in my eyes you just rely on undefined behaviour.