public inbox for glibc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug stdio/27821] New: double call to ungetc causes uninitalized memory reading. (also: ungetc causes memory leak)
@ 2021-05-04  6:35 jrogers at opera dot com
  0 siblings, 0 replies; only message in thread
From: jrogers at opera dot com @ 2021-05-04  6:35 UTC (permalink / raw)
  To: glibc-bugs

https://sourceware.org/bugzilla/show_bug.cgi?id=27821

            Bug ID: 27821
           Summary: double call to ungetc causes uninitalized memory
                    reading. (also: ungetc causes memory leak)
           Product: glibc
           Version: 2.31
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: stdio
          Assignee: unassigned at sourceware dot org
          Reporter: jrogers at opera dot com
  Target Milestone: ---

Hi,

In C11, 7.21.7.10 #3 it is said that for the function ungetc, "one character of
pushback is guaranteed. If the ungetc function is called too many times on the
same stream without an intervening read or file positioning operation on
thatstream, the operation may fail."

This is in contrast, to say, some sort of undefined behavior.

https://linux.die.net/man/3/ungetc confirms this: "ungetc() pushes c back to
stream, cast to unsigned char, where it is available for subsequent read
operations. Pushed-back characters will be returned in reverse order; only one
pushback is guaranteed."


However, when using glibc 2.31, this does not happen, and instead there is a
case of uninitalized memory reading happening upon the second byte being passed
to ungetc()

The following code, ran with valgrind, produces an at least :
#include <stdio.h>
int main(void)
{
    int i;
    for (i = 0; i < 4096; i++)
    {
        int c = i % 16 + 64;
        if (ungetc(c, stdin) != c)
        {
            fprintf(stderr, "Error at count = %d\n", i);
            return(1);
        }
    }
    printf("No error up to count = %d\n", i-1);
    return(0);
}



==2046557== Conditional jump or move depends on uninitialised value(s)
==2046557==    at 0x48F0A9B: _IO_sputbackc (genops.c:639)
==2046557==    by 0x1091C5: main (in /tmp/a.out)
==2046557==  Uninitialised value was created by a heap allocation
==2046557==    at 0x483B7F3: malloc (in
/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==2046557==    by 0x48F1919: _IO_default_pbackfail (genops.c:995)
==2046557==    by 0x48F0AC5: _IO_sputbackc (genops.c:645)
==2046557==    by 0x1091C5: main (in /tmp/a.out)
==2046557== 
No error up to count = 4095
==2050170== 4090 errors in context 1 of 2:
==2050170== Conditional jump or move depends on uninitialised value(s)
==2050170==    at 0x48F0A9B: _IO_sputbackc (genops.c:639)
==2050170==    by 0x4011A3: main (a.c:8)




I find it strange that only 4090-cases of uninitalized memory are detected by
valgrind rather than 4094 but that's a different matter.

I believe ungetc() should either simply not work when called in multiple
successions as it is said in the documentation, or it should work; it should
not work but with uninitalized memory reads.


On a related note, ungetc() seems to cause a memory leak if you push a
character back to stdin, but stdin is empty.

#include <stdio.h>
int main(void)
{   
   ungetc('1', stdin);
   putchar(getchar());
    return(0);
}

$ echo 'whatever' | valgrind ./a.out
$ 1
[...]
==2057370==    definitely lost: 128 bytes in 1 blocks




While I know I am not using ungetc correctly here, I guess it is not deliberate
to 1) read uninitalized memory, and 2) leak memory. Happy to be wrong though.

Thank you.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-05-04  6:35 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-04  6:35 [Bug stdio/27821] New: double call to ungetc causes uninitalized memory reading. (also: ungetc causes memory leak) jrogers at opera dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).