Bug in fmemopen() or my program?
Dustin Boyd
memreflect@pm.me
Sat Sep 19 03:10:11 GMT 2020
Thank you for responding.
After reviewing the Single Unix Specification information, I think
you may be correct. It's just really odd that opening a stream with
mode "w" or "w+" MUST write a null byte while opening with mode "r+",
"a", or "a+" MAY write a null byte.
That means modes "w" and "w+" effectively follow the behavior of the
BSD function strlcat(), always terminating the buffer with a null
byte, while the other 3 modes follow strncat() behavior, only
terminating the buffer with a null byte if there is room left in the
buffer. Naturally this causes data truncation.
I now understand that fmemopen() was designed for manipulating strings
in a way that prevents buffer overflows, and that a mode containing
'b' is implementation-defined (unsupported in glibc), suggesting that
the only portable usage is with textual data, which means
null-terminated strings in this case.
That said, I still prefer the FreeBSD implementation since it provides
consistent behavior, no matter which mode is used, but I at least
understand the logic of the glibc implementation with respect to the
Single Unix Specification text.
One could argue that "w+" is different than "w" since it is "open for
updating", not "open for writing", or that all modes other than "r"
(and "rb") open a stream that is technically "open for writing", which
can cause further trouble. I won't be the one to raise such issues,
but I do believe those points can result in exactly the confusion that
led to my concerns: differing implementations as a consequence of
different interpretations. Hopefully this situation is recognized and
rectified in the next issue of the SUS?
Thank you again,
Dustin Boyd
On Saturday, September 19, 2020 4:55 PM, Joseph C. Sible <josephcsible@gmail.com> wrote:
> This sentence from
> https://pubs.opengroup.org/onlinepubs/9699919799.2016edition/functions/fmemopen.html
> looks relevant: "When a stream open for writing is flushed or closed,
> a null byte shall be written at the current position or at the end of
> the buffer, depending on the size of the contents." To me, that sounds
> like it always has to put a null byte somewhere, overwriting the last
> character if it has to, and that it's FreeBSD that has a bug, since it
> doesn't do that.
>
> Joseph C. Sible
>
> On Fri, Sep 18, 2020, 12:12 Dustin Boyd via Libc-help
> libc-help@sourceware.org wrote:
>
> > I have the following program:
> > #include <stdio.h>
> > #include <string.h>
> > #define BYE "goodbye"
> > #define SIZE (sizeof (BYE) - 1)
> > int
> > main (void)
> > {
> > char buf[SIZE];
> > FILE* f;
> > size_t nwr, len;
> > f = fmemopen (buf, SIZE, "w+");
> > nwr = fwrite (BYE, 1, SIZE, f);
> > fclose (f);
> > len = strnlen (buf, SIZE);
> > printf ("siz %zu\n", SIZE);
> > printf ("nwr %zu\n", nwr);
> > printf ("len %zu\n", len);
> > printf ("buf %.*s\n", (int) len, buf);
> > }
> > Output:
> > Debian Fedora FreeBSD
> > siz 7 7 7
> > nwr 7 7 7
> > len 6 6 7
> > buf goodby goodby goodbye
> > According to the Single Unix Specification, a null byte is only
> > written at the end of the buffer on flush/close when there is space
> > left in the buffer.
> > I wrote 7 bytes as indicated by the return value of fwrite(), and the
> > size of the buffer is 7 bytes, so no space remains in the buffer.
> > Why is a null byte being written here? Am I overlooking something
> > important about fmemopen(), or is it a bug in glibc's implementation?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 509 bytes
Desc: OpenPGP digital signature
URL: <https://sourceware.org/pipermail/libc-help/attachments/20200919/059d901b/attachment.sig>
More information about the Libc-help
mailing list