[PATCH v2] libio: Fix fmemopen_write on appending condition
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Thu Mar 26 12:21:31 GMT 2026
On 25/03/26 01:02, Rocket Ma wrote:
> Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> 于2026年3月25日周三 04:26写道:
>> I think setbuf is not strictly required here, with this fix fclose does write
>> on the input buffer. It also masks a potential issue, as below. I think we
>> need to test *all* possible buffer modes.
>
> I know what you mean, but I think this patch should be simple enough to fix only
> one issue, we could discuss another patch to test other modes to fix Bug 34006.
The problem with this patch it although it fixes the fmemopen result it
adds another inconsistent with fflush/fclose. And I don't think we should
partially fix, the glibc current behavior might not be following POSIX
but it is still consistent wrt error reporting.
>
>> Yes, and I agree with your rationale. The issue is, with this patch,
>> fclose in buffered mode (the default) now returns a failure *without*
>> setting errno and this is inconsistent.
>
> I tested it in https://sourceware.org/bugzilla/show_bug.cgi?id=34006#c1
> I think we could fix it in another patch to leave this patch clean and neat.
I don't agree, fflush/fclose will keep returning an error but now the input
buffer is also modified. This is unexpected and inconsistent.
If the buffer is not correctly modified we need also to proper signal the
operation to the caller.
>
>> I am not sure if fmemopen_write should hide that less bytes are written
>> in the input buffer (thus running 's') or if we should fix it on the
>> fwrite (so it only advances its internal position 3 instead of 4 and
>> then issues fmemopen_write with s=3 instead of s4).
>
> I do think we should advance s=4 instead of 3 according to POSIX.1-2024.
> Or I misunderstand?
My understanding from fmemopen POSIX description is:
"[...] A write operation on the stream shall *not* advance the current
buffer end position beyond the size given in the max_size argument. [...]"
And I would consider the less expected behavior fwrite to actually return
the number of bytes it can actually write, instead of relying on fflush/fclose
to truncate the buffer.
>
>> I think we should have the fmemopen size information somewhere in the
>> FILE so _IO_file_doallocate can allocate a buffer with a size limit
>> instead of a BUFSIZ one. One we can init the buffer size on __fmemopen,
>> but it pessimize memory allocation on FILE creation instead of when
>> data is actually done. Something as below:
>>
>> It has the size effect of making a fwrite that overflow the input
>> buffer to signal the numbers of bytes that will be written in a fflush
>> or fclose, instead of silent fail. But it triggers a regression
>> on stdio-common/tst-fmemopen2 because it seems that we do expect this
>> for buffer size of 0 (not sure if this test is fully valid though).
>
> I don't think glibc should fail fast on fwrite. I mounted a tmpfs with 4k size,
> then write to it with buffered IO, each time 0x1000 and then flush,
> here is the result:
>
> fwrite 0x1000 = 0x1000
> fflush = 0
> fwrite 0x1000 = 0x1000
> fclose = 0xffffffffffffffff No space left on device
>
> The source is attached below. In this case, since filesystem FILE
> behave like this,
> then why should we fail directly on fwrite?
Well, the rationale of fmemopen addition was to
"eliminate many of the errors encountered in the construction of strings"
So I am not sure if we apply the same ideas of FILE access, specially because
silent string truncation is still a source of issue.
At least FreeBSD does return the remaining bytes on fwrite operations (and
I assume other BSD as well).
>
> ---
>
> int main(void) {
> FILE *fp = fopen("tmpfs/1", "wb");
> setvbuf(fp, NULL, _IOFBF, 0x2200);
> char *spc = malloc(0x2000);
> memset(spc, 'A', 0x2000);
> long rc = fwrite(spc, 1, 0x1000, fp);
> printf("fwrite 0x1000 = %#lx\n", rc);
> rc = fflush(fp);
> printf("fflush = %#lx\n", rc);
> rc = fwrite(spc, 1, 0x1000, fp);
> printf("fwrite 0x1000 = %#lx\n", rc);
> rc = fclose(fp);
> printf("fclose = %#lx %m\n", rc);
> return 0;
> }
More information about the Libc-alpha
mailing list