[PATCH] libio: null terminate the buffer upon initial allocation in getdelim
Collin Funk
collin.funk1@gmail.com
Tue Nov 18 05:26:32 GMT 2025
Eric Blake <eblake@redhat.com> writes:
> On Fri, Nov 14, 2025 at 09:25:36PM -0800, Collin Funk wrote:
>> Commit 33eff78c8b28adc4963987880e10d96761f2a167 caused issues in nbdkit
>> which had code similar to this to get the last line of the file:
>>
>> while (getline (&line, &len, fp) != -1)
>> ;
>> /* Process LINE. */
>>
>> After that commit, line[0] would be equal to '\0' instead of containing
>> the last line of the file like before that commit.
>>
>> This patch null terminates the buffer upon getdelim/getline's initial
>> allocation. This is compatible with previous glibc versions, while also
>> protecting the caller from reading uninitialized memory if the file is
>> empty, as long as getline/getdelim does the initial allocation.
>> ---
>
> Looks like it matches my idea.
Yes, that is what it was based on. I should have added a
"Suggested-by:".
>> +++ b/libio/tst-getdelim.c
>> @@ -51,11 +51,9 @@ do_test (void)
>> xfclose (memstream);
>> free (lineptr);
>>
>> - /* Test that getdelim NUL terminates upon reading an EOF from an empty
>> - file (BZ #28038). This test fails on glibc 2.42 and earlier. */
>> - lineptr = xmalloc (1);
>> - lineptr[0] = 'A';
>> - linelen = 1;
>> + /* Test that we null-terminate the buffer upon allocating it (BZ #28038). */
>> + lineptr = NULL;
>> + linelen = 0;
>
> Does linelen have to be initialized to any paticular value when
> lineptr is passed in as NULL?
For glibc it doesn't matter since we check if *LINEPTR == NULL first:
if (*lineptr == NULL || *n == 0)
{
[...]
}
I would be worried about passing it in uninitialized since an
implementation might access it.
Based on my reading of the standard the allocation is done if
*LINEPTR == NULL and then *n will be updated. So initializing it to
anything should be fine. Setting it to something other than 0 would look
strange, in my opinion.
>> char *file_name;
>> TEST_VERIFY_EXIT (create_temp_file ("tst-getdelim.", &file_name) != -1);
>> FILE *fp = fopen (file_name, "r");
>> diff --git a/manual/stdio.texi b/manual/stdio.texi
>> index e8f60b09c1..4e5b890cf0 100644
>> --- a/manual/stdio.texi
>> +++ b/manual/stdio.texi
>> @@ -1279,7 +1279,12 @@ @node Line Input
>> POSIX.1-2008.
>>
>> If an error occurs or end of file is reached without any bytes read,
>> -@code{getline} returns @code{-1}.
>> +@code{getline} returns @code{-1}. POSIX leaves the contents of
>> +@code{*@var{lineptr}} undefined when @code{getline} returns @code{-1}.
>> +If the the @glibcadj{} implementation of @code{getline} allocates the
>
> duplicate "the"
Oops, I will remove that locally.
Thanks,
Collin
[1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html
More information about the Libc-alpha
mailing list