1

Solved with glibc 2.24 -- See UPDATE below

Here is a piece of C-Code (compiled with gcc 5.3.1, glibc 2.23):

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

int main() {
  const char* s1="Original content of file.\n"
                 "still original content and some remaining original content.\n";
  const char* s2="overwriting data  with new content\n";
  const char* s3="appended data\n";

  const size_t bufsz=strlen(s1)+1;
  char buf[bufsz];
  FILE *f;
  int r;

  f=fmemopen(buf,bufsz,"w");
  assert(f!=NULL);

  // setbuf(f, NULL);          // variant no. 1
  // setbuffer(f, buf, bufsz); // variant no. 2

  r=fwrite(s1,strlen(s1),1,f);
  assert(r==1);

  r=fflush(f);
  assert(r==0);

  rewind(f);

  r=fwrite(s2,strlen(s2),1,f);
  assert(r==1);

  r=fwrite(s3,strlen(s3),1,f);
  assert(r==1);

  r=fclose(f);
  assert(r==0);

  printf("%s",buf);
}
  • It does what I expect -- The output is:

    overwriting data  with new content
    appended data
    and some remaining original content.
    
  • Now, the manpage fmemopen(3) advices to either disable buffering (uncomment variant 1), or to explicitely set buf as buffer (uncomment variant 2).

    However, in both cases, I get as result:

    appended data
    ta  with new content
    ginal content and some remaining original content.
    

    Thus, the appended data was not written after the second content, as expected, but did overwrite the second content.

  • The behaviour remains the same if I open the file in binary mode (i.e. replacing the "w" mode by "wb").

  • valgrind does not report any errors (Except a false positive "Source and destination overlap" in the case of buffering. The latter one is due to the try to write the STDIO buffer into the memory, which is indeed the same address.)

What is wrong? Did I make a mistake? Or is this a GLIBC bug?

UPDATE

On August 4th, a new glibc version 2.24 was released. With gcc 5.4.0 and glibc 2.24, variant no. 1 (unbuffered FILE) works fine. Variant 2 (self-buffered version) gives a different, but still erroneous result. Thus I believe R.. is right in claiming that this is a documentation bug in the manpage fmemopen(3). I will raise a bug report ...

ralfg
  • 552
  • 2
  • 11
  • 1
    My results differ. I get the "expected" output on both your code as posted **and** with uncommented variant 1. (GCC 4.8) – DevSolar Aug 09 '16 at 15:06
  • 1
    Does flushing the stream before rewinding make any difference? – Ian Abbott Aug 09 '16 at 15:32
  • @Ian Abott: An additional `fflush(f);` directly before rewinding does not change the behaviour in any of the variants. Return value of fflush(f) is 0 in all cases. – ralfg Aug 10 '16 at 06:12

1 Answers1

2

Now, the manpage fmemopen(3) advices to either disable buffering (uncomment variant 1), or to explicitely set buf as buffer (uncomment variant 2).

The latter is most certainly undefined behavior. Don't do it. It's not clear to me what the text you found in the Linux man page:

Alternatively, the caller can explicitly set buf as the stdio stream buffer, at the same time informing stdio of the buffer's size, using:

setbuffer(stream, buf, size);

is trying to express, but it's a documentation bug and should probably just be removed.

As for unbuffered mode not working, this is probably a glibc bug. Try to make the test case as minimal as you can, test against a recent glibc, and if it still happens, submit a bug report on the glibc bugzilla:

https://sourceware.org/bugzilla/enter_bug.cgi?product=glibc

A safe alternative when you want to know immediately about errors is just calling fflush and checking the return value.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Thank you. I downloaded the just newly released glibc 2.24, and the behaviour is now correct in variant 1, and still incorrect (but different) in variant 2. – ralfg Aug 10 '16 at 07:52
  • Variant 2 is a bug in your program. It's not valid usage. The man pages project has already been fixed upstream not to make this wrong recommendation. – R.. GitHub STOP HELPING ICE Aug 10 '16 at 13:24