lseek(fd, 0, SEEK_CUR) returns unexpected result for O_APPEND file on linux 2.6.32-431.29.2

From: Sigurd NÃss
Date: Fri Oct 23 2015 - 20:18:18 EST


Below is a description of a simple test case that causes lseek(fd, 0,
SEEK_CUR) to return an unexpectedly small result on one of my
computers, with linux 2.6.32-431.29.2, but none of the others. I'm
posting it on the off chance that this is (or was) a kernel bug, and
not some problem on my end.

The program below creates a file containing the string
"01234", closes it, then opens it for appending, writes "a"
to it (which should be appended, creating "01234a"), truncates
it to the current position in the file (the end, and hence a no-op),
and finally writes "b", resulting in "01234ab".

This is indeed the result on most systems I've run it on, for example
$ uname -a Linux regulus.uio.no 2.6.32-573.7.1.el6.x86_64 #1 SMP Thu
Sep 10 13:42:16 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux
$ gcc -o append_bug{,.c}
$ ./append_bug; cat foo.txt; echo
$01234ab

However, on one system with linux 2.6.32-431.29.2, the program gives
unexpected results because lseek returns 1 rather than the expected 6,
resulting in the output "0b".
$ uname -a Linux nekkar.uio.no 2.6.32-431.29.2.el6.x86_64 #1 SMP Sun
Jul 27 15:55:46 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux
$ gcc -o append_bug{,.c}
$ ./append_bug; cat foo.txt; echo
0b

$ cat append_bug.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char ** argv)
{
int f; off_t n;
f = open("foo.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
write(f, "01234", 5);
close(f);

f = open("foo.txt", O_WRONLY|O_APPEND);
write(f, "a", 1);
n = lseek(f, 0, SEEK_CUR);
ftruncate(f, n);
write(f, "b", 1);
close(f);
}

The version of gcc used was the rather old 4.4.7, but the compiler
version appears to be irrelevant - the executable from the
computer that exhibits the behavior does not do so when run
on e.g. my linux 2.6.32-573.7.1 computer. I reproduce the same
problem with icc. It occurs uniformly across all the 2.6.32-431.29.2
computers I have access to.

Could this be a kernel bug that was fixed between these
linux versions? If so, my google and lkml searches have not
turned up any mention of it (thought I did find patch that mentions
a marginally similar-sounding issue (https://lkml.org/lkml/2008/11/10/369).

The behavior was originally discovered when a colleague of mine
experienced that using shell redirection to append stdout of a fortran
program compiled with ifort resulted in the output file being truncated.
E.g. fortprog >> foo.txt would truncate rather than appending.
The strange write, lseek, ftruncate, write procedure used in
this program is a replica of ifort behavior, which only results in
incorrect results in the presence of this bug.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/