fseek/fgetc puzzle

Darren Tucker dtucker at dtucker.net
Fri Feb 17 19:07:12 AEDT 2023


Hi all.

I've got a bit of a puzzle and I was wondering if anyone has any insight
as to what's going on.

I added some code to ssh's known_hosts handling that checks if the last
byte in the file is a newline, and if not, it adds one before writing
the new record.  I also wrote a regression test for this and in most
cases this works fine.

On some platforms (Solaris, OpenIndiana and AIX) however, the test fails
because it adds two newlines instead of the expected one.  Basically if
I fseek to the end, read a byte and write a byte the first byte will
be duplicated.  I reduced it to this test case:

#include <stdio.h>
int main(void)
{
        FILE *f = fopen("testfile", "w");
        putc('A', f);
        fclose(f);

        f = fopen("testfile", "a+");  /* same behaviour for r+ */
        fseek(f, -1L, SEEK_END);
        printf("c=%d\n", fgetc(f));
        /* fseek(f, 0, SEEK_END);  -- with this it behaves as expected */
        /* fflush(f);  -- this too */
        fputc('B', f);
}

$ gcc test.c && ./a.out; od -x -c testfile
c=65
0000000    4141    0042
           A   A   B
0000003

I wrote two bytes and read one but somehow ended up with three bytes in
the file?  (This example is from Solaris 11 but AIX does the same thing).

On most platforms this behaves as expected:

$ cc test.c && ./a.out; od -x -c testfile
c=65
0000000     4241
           A   B
0000002

Now I could just add the fseek, but as far as I can tell I shouldn't
have to, and I don't understand why.  I've read the specs and the man
pages and haven't found anything that would explain this behaviour.

I'm curious if anyone has a) any insight as to what's going on, or b)
any additional examples of where it fails?

Thanks.

-- 
Darren Tucker (dtucker at dtucker.net)
GPG key 11EAA6FA / A86E 3E07 5B19 5880 E860  37F4 9357 ECEF 11EA A6FA (new)
    Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.


More information about the openssh-unix-dev mailing list