0

I ran the following test after trying to help someone with a piece of Python code; I know the test is simple but I can't figure out why this happens.

The basic idea is this: I have the following C code:

#include <stdlib.h>
#include <stdio.h>

int main() {
    FILE *pf = fopen("test.txt", "r+");
    char buf[100];
    fgets(buf, 100, pf);
    fseek(pf, -7, SEEK_CUR);
    fwrite("0", 1, 1, pf);
    //NEXT LINE PROBLEMATIC
    fgets(buf, 100, pf);
    fclose(pf);
    return 0;
}

and the input file containing one line: abcdefghijklmnopqrstuvwxyz

I would expect the output to contain a zero inside the string; however, this happens: abcdefghijklmnopqrs0bcdefghijklmnopqrstuvwxyz

(there are multiple space characters after the text). If I comment out the problematic line (the second call to fgets), the output works as expected.

Does anybody have any idea why that happens?

To me it seemed like a buffer overflow because of the space characters after the end of the line; reproducing using cl.exe instead of gcc I get this: abcdefghijklmnopqrs0bcdefghijklmnopqrstuvwxyzt e s t e \ p y _ w e i r d \ t e s t . t x t c l e ;i À ] h&^ u a

So it's definitely an overflow caused, most likely, by interweaving calls to fgets with calls to fseek/fwrite.

AdrianH
  • 76
  • 5
  • 1
    I suspect it's a problem with buffered IO. Use `fflush(pf)` after `fwrite()`. – EOF Feb 05 '15 at 19:28
  • EOF, you're right, adding the `fflush` right after `fwrite()` makes it work correctly. Still, the buffer is small, I don't understand what goes on underneath. – AdrianH Feb 05 '15 at 19:31
  • The buffer is invisible to you. It is likely 4K. – stark Feb 05 '15 at 19:32
  • It will be good to add error checking code around `fwrite` and `fgets` to make sure that the code does what you expect it to. – R Sahu Feb 05 '15 at 19:32
  • n.m., thanks for the reference, I didn't find that one when looking. I've just read it and, as I assumed, it's a buffering problem but I can't get it. The thing is, this comes from a piece of Python code calling fgets! – AdrianH Feb 05 '15 at 19:36
  • @stark, I was referring to my own, temporary buffer `buf[100]`. – AdrianH Feb 05 '15 at 19:37
  • What output are you talking about ? There is no output in your program. – Jean-Baptiste Yunès Feb 05 '15 at 22:12

2 Answers2

0

If anybody finds this, n.m.'s suggestion is correct, I don't know why I couldn't find it when I first search. See the answer here: why fseek or fflush is always required between reading and writing in the read/write "+" modes

Someone with more reputation, please mark as a duplicate and close :)

Community
  • 1
  • 1
AdrianH
  • 76
  • 5
-1

Nothing surnatural...

This reads the 26 alphabetic chars and the current offset will be set to 26:

fgets(buf, 100, pf);

This sets the current offset to 19, so pointing to the 20th char of the alphabet t:

fseek(pf, -7, SEEK_CUR);

Then this writes 0 over t and set the offset to 20:

fwrite("0", 1, 1, pf);

This reads the remaining chars uvwxyz in buf and set the offset to 26: fgets(buf, 100, pf);

So at the end you will have abcdefghijklmnopqrs0uvwxyz in the file.

What's in the buffer is the content of the last read, which is necessarily uvwxyz (the six last chars of the file, no doubt) as nothing was done to modify them and there is only one offset per open file.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69