juhist juhist - 1 year ago 61
C Question

fmemopen gives a Valgrind error

I have the following code:

char *filedata;
FILE *f;
filedata = malloc(3);
if (filedata == NULL)
fprintf(stderr, "out of memory\n");
memcpy(filedata, "foo", 3);
f = fmemopen(filedata, 3, "r");
if (f == NULL)
fprintf(stderr, "out of memory\n");

Now, when I execute this with Valgrind, I get the following error:

==32454== Invalid read of size 1
==32454== at 0x4006D33: __GI_strlen (mc_replace_strmem.c:284)
==32454== by 0x855B7E: fmemopen (fmemopen.c:246)
==32454== by 0x80485BF: main (in /home/tilli/memopen/a.out)
==32454== Address 0x402502b is 0 bytes after a block of size 3 alloc'd
==32454== at 0x4005BDC: malloc (vg_replace_malloc.c:195)
==32454== by 0x8048548: main (in /home/tilli/memopen/a.out)

It seems like
is doing an
for the argument I passed to it. However, the manual page says that the buffer argument to
can be a string or a memory buffer (so it doesn't have to be
-terminated). Furthermore, it says that the argument must be at least
bytes long, which it is.

What is wrong here? Have I just a found a bug in the library function
? Am I correct that in extreme cases this bug could crash a program using
if the
doesn't find a
terminator but instead continues to read unmapped memory?

I'm running Fedora release 12.

Answer Source

From the manual it looks like the \0 is used as EOF marker for stream buffers unless the mode includes a b. This explains why a strlen() would be used to locate the EOF.

From man fmemopen:

The argument mode is the same as for fopen(3). If mode specifies an append mode, then the initial file position is set to the location of the first null byte ('\0') in the buffer; otherwise the initial file position is set to the start of the buffer. Since glibc 2.9, the letter 'b' may be specified as the second character in mode. This provides "binary" mode: writes don't implicitly add a terminating null byte, and fseek(3) SEEK_END is rela‐ tive to the end of the buffer (i.e., the value specified by the size argument), rather than the current string length.

However, in the same man we can read :

In a stream opened for reading, null bytes ('\0') in the buffer do not cause read operations to return an end- of-file indication. A read from the buffer will only indicate end-of-file when the file pointer advances size bytes past the start of the buffer.

So you might have found a bug.