mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-29 11:41:21 +03:00
libio: Use stdin consistently for input functions [BZ #24153]
The internal _IO_stdin_ variable is not updated when the application assigns to stdin, which is a GNU extension.
This commit is contained in:
14
ChangeLog
14
ChangeLog
@ -1,3 +1,17 @@
|
|||||||
|
2019-02-03 Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
[BZ #24153]
|
||||||
|
* debug/gets_chk.c (__gets_chk): Use stdin instead of _IO_stdin.
|
||||||
|
* libio/getchar.c (getchar): Likewise.
|
||||||
|
* libio/getchar_u.c (getchar_unlocked): Likewise.
|
||||||
|
* libio/getwchar.c (getwchar): Likewise.
|
||||||
|
* libio/getwchar_u.c (getwchar_unlocked): Likewise.
|
||||||
|
* libio/iogets.c (_IO_gets): Likewise.
|
||||||
|
* libio/vscanf.c (_IO_vscanf): Likewise.
|
||||||
|
* libio/vwscanf.c (__vwscanf): Likewise.
|
||||||
|
* libio/tst-bz24153.c: New file.
|
||||||
|
* libio/Makefile (tests): Add it.
|
||||||
|
|
||||||
2019-02-02 Florian Weimer <fweimer@redhat.com>
|
2019-02-02 Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
[BZ #14829]
|
[BZ #14829]
|
||||||
|
@ -37,8 +37,8 @@ __gets_chk (char *buf, size_t size)
|
|||||||
if (size == 0)
|
if (size == 0)
|
||||||
__chk_fail ();
|
__chk_fail ();
|
||||||
|
|
||||||
_IO_acquire_lock (_IO_stdin);
|
_IO_acquire_lock (stdin);
|
||||||
ch = _IO_getc_unlocked (_IO_stdin);
|
ch = _IO_getc_unlocked (stdin);
|
||||||
if (ch == EOF)
|
if (ch == EOF)
|
||||||
{
|
{
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
@ -51,24 +51,24 @@ __gets_chk (char *buf, size_t size)
|
|||||||
/* This is very tricky since a file descriptor may be in the
|
/* This is very tricky since a file descriptor may be in the
|
||||||
non-blocking mode. The error flag doesn't mean much in this
|
non-blocking mode. The error flag doesn't mean much in this
|
||||||
case. We return an error only when there is a new error. */
|
case. We return an error only when there is a new error. */
|
||||||
int old_error = _IO_stdin->_flags & _IO_ERR_SEEN;
|
int old_error = stdin->_flags & _IO_ERR_SEEN;
|
||||||
_IO_stdin->_flags &= ~_IO_ERR_SEEN;
|
stdin->_flags &= ~_IO_ERR_SEEN;
|
||||||
buf[0] = (char) ch;
|
buf[0] = (char) ch;
|
||||||
count = _IO_getline (_IO_stdin, buf + 1, size - 1, '\n', 0) + 1;
|
count = _IO_getline (stdin, buf + 1, size - 1, '\n', 0) + 1;
|
||||||
if (_IO_stdin->_flags & _IO_ERR_SEEN)
|
if (stdin->_flags & _IO_ERR_SEEN)
|
||||||
{
|
{
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
goto unlock_return;
|
goto unlock_return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_IO_stdin->_flags |= old_error;
|
stdin->_flags |= old_error;
|
||||||
}
|
}
|
||||||
if (count >= size)
|
if (count >= size)
|
||||||
__chk_fail ();
|
__chk_fail ();
|
||||||
buf[count] = 0;
|
buf[count] = 0;
|
||||||
retval = buf;
|
retval = buf;
|
||||||
unlock_return:
|
unlock_return:
|
||||||
_IO_release_lock (_IO_stdin);
|
_IO_release_lock (stdin);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
|
|||||||
tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
|
tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
|
||||||
tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
|
tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
|
||||||
tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
|
tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
|
||||||
tst-sprintf-ub tst-sprintf-chk-ub tst-bz24051
|
tst-sprintf-ub tst-sprintf-chk-ub tst-bz24051 tst-bz24153
|
||||||
|
|
||||||
tests-internal = tst-vtables tst-vtables-interposed tst-readline
|
tests-internal = tst-vtables tst-vtables-interposed tst-readline
|
||||||
|
|
||||||
|
@ -33,11 +33,11 @@ int
|
|||||||
getchar (void)
|
getchar (void)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
if (!_IO_need_lock (_IO_stdin))
|
if (!_IO_need_lock (stdin))
|
||||||
return _IO_getc_unlocked (_IO_stdin);
|
return _IO_getc_unlocked (stdin);
|
||||||
_IO_acquire_lock (_IO_stdin);
|
_IO_acquire_lock (stdin);
|
||||||
result = _IO_getc_unlocked (_IO_stdin);
|
result = _IO_getc_unlocked (stdin);
|
||||||
_IO_release_lock (_IO_stdin);
|
_IO_release_lock (stdin);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,5 +32,5 @@
|
|||||||
int
|
int
|
||||||
getchar_unlocked (void)
|
getchar_unlocked (void)
|
||||||
{
|
{
|
||||||
return _IO_getc_unlocked (_IO_stdin);
|
return _IO_getc_unlocked (stdin);
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,8 @@ wint_t
|
|||||||
getwchar (void)
|
getwchar (void)
|
||||||
{
|
{
|
||||||
wint_t result;
|
wint_t result;
|
||||||
_IO_acquire_lock (_IO_stdin);
|
_IO_acquire_lock (stdin);
|
||||||
result = _IO_getwc_unlocked (_IO_stdin);
|
result = _IO_getwc_unlocked (stdin);
|
||||||
_IO_release_lock (_IO_stdin);
|
_IO_release_lock (stdin);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -32,5 +32,5 @@
|
|||||||
wint_t
|
wint_t
|
||||||
getwchar_unlocked (void)
|
getwchar_unlocked (void)
|
||||||
{
|
{
|
||||||
return _IO_getwc_unlocked (_IO_stdin);
|
return _IO_getwc_unlocked (stdin);
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,8 @@ _IO_gets (char *buf)
|
|||||||
int ch;
|
int ch;
|
||||||
char *retval;
|
char *retval;
|
||||||
|
|
||||||
_IO_acquire_lock (_IO_stdin);
|
_IO_acquire_lock (stdin);
|
||||||
ch = _IO_getc_unlocked (_IO_stdin);
|
ch = _IO_getc_unlocked (stdin);
|
||||||
if (ch == EOF)
|
if (ch == EOF)
|
||||||
{
|
{
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
@ -48,22 +48,22 @@ _IO_gets (char *buf)
|
|||||||
/* This is very tricky since a file descriptor may be in the
|
/* This is very tricky since a file descriptor may be in the
|
||||||
non-blocking mode. The error flag doesn't mean much in this
|
non-blocking mode. The error flag doesn't mean much in this
|
||||||
case. We return an error only when there is a new error. */
|
case. We return an error only when there is a new error. */
|
||||||
int old_error = _IO_stdin->_flags & _IO_ERR_SEEN;
|
int old_error = stdin->_flags & _IO_ERR_SEEN;
|
||||||
_IO_stdin->_flags &= ~_IO_ERR_SEEN;
|
stdin->_flags &= ~_IO_ERR_SEEN;
|
||||||
buf[0] = (char) ch;
|
buf[0] = (char) ch;
|
||||||
count = _IO_getline (_IO_stdin, buf + 1, INT_MAX, '\n', 0) + 1;
|
count = _IO_getline (stdin, buf + 1, INT_MAX, '\n', 0) + 1;
|
||||||
if (_IO_stdin->_flags & _IO_ERR_SEEN)
|
if (stdin->_flags & _IO_ERR_SEEN)
|
||||||
{
|
{
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
goto unlock_return;
|
goto unlock_return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_IO_stdin->_flags |= old_error;
|
stdin->_flags |= old_error;
|
||||||
}
|
}
|
||||||
buf[count] = 0;
|
buf[count] = 0;
|
||||||
retval = buf;
|
retval = buf;
|
||||||
unlock_return:
|
unlock_return:
|
||||||
_IO_release_lock (_IO_stdin);
|
_IO_release_lock (stdin);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
114
libio/tst-bz24153.c
Normal file
114
libio/tst-bz24153.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/* Test that assigning to stdin redirects input (bug 24153).
|
||||||
|
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Prevent getchar -> getc inline expansion. */
|
||||||
|
#define __NO_INLINE__
|
||||||
|
#pragma GCC optimize ("O0")
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <support/check.h>
|
||||||
|
#include <support/temp_file.h>
|
||||||
|
#include <support/xstdio.h>
|
||||||
|
#include <support/xunistd.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
call_vscanf (const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start (ap, format);
|
||||||
|
int ret = vscanf (format, ap);
|
||||||
|
va_end (ap);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
call_vwscanf (const wchar_t *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start (ap, format);
|
||||||
|
int ret = vwscanf (format, ap);
|
||||||
|
va_end (ap);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
narrow (const char *path)
|
||||||
|
{
|
||||||
|
FILE *old_stdin = stdin;
|
||||||
|
stdin = xfopen (path, "r");
|
||||||
|
|
||||||
|
TEST_COMPARE (getchar (), 'a');
|
||||||
|
TEST_COMPARE (getchar_unlocked (), 'b');
|
||||||
|
char ch = 1;
|
||||||
|
TEST_COMPARE (scanf ("%c", &ch), 1);
|
||||||
|
TEST_COMPARE (ch, 'c');
|
||||||
|
TEST_COMPARE (call_vscanf ("%c", &ch), 1);
|
||||||
|
TEST_COMPARE (ch, 'd');
|
||||||
|
char buf[8];
|
||||||
|
memset (buf, 'X', sizeof (buf));
|
||||||
|
|
||||||
|
/* Legacy interface. */
|
||||||
|
extern char *gets (char *);
|
||||||
|
TEST_VERIFY (gets (buf) == buf);
|
||||||
|
TEST_COMPARE_BLOB (buf, sizeof (buf), "ef\0XXXXX", sizeof (buf));
|
||||||
|
|
||||||
|
fclose (stdin);
|
||||||
|
stdin = old_stdin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wide (const char *path)
|
||||||
|
{
|
||||||
|
FILE *old_stdin = stdin;
|
||||||
|
stdin = xfopen (path, "r");
|
||||||
|
|
||||||
|
TEST_COMPARE (getwchar (), L'a');
|
||||||
|
TEST_COMPARE (getwchar_unlocked (), L'b');
|
||||||
|
wchar_t ch = 1;
|
||||||
|
TEST_COMPARE (wscanf (L"%c", &ch), 1);
|
||||||
|
TEST_COMPARE (ch, L'c');
|
||||||
|
TEST_COMPARE (call_vwscanf (L"%c", &ch), 1);
|
||||||
|
TEST_COMPARE (ch, L'd');
|
||||||
|
|
||||||
|
fclose (stdin);
|
||||||
|
stdin = old_stdin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_test (void)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
{
|
||||||
|
int fd = create_temp_file ("tst-bz24153-", &path);
|
||||||
|
TEST_VERIFY_EXIT (fd >= 0);
|
||||||
|
xwrite (fd, "abcdef", strlen ("abcdef"));
|
||||||
|
xclose (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
narrow (path);
|
||||||
|
wide (path);
|
||||||
|
|
||||||
|
free (path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <support/test-driver.c>
|
@ -37,6 +37,6 @@
|
|||||||
int
|
int
|
||||||
_IO_vscanf (const char *format, va_list args)
|
_IO_vscanf (const char *format, va_list args)
|
||||||
{
|
{
|
||||||
return __vfscanf_internal (_IO_stdin, format, args, 0);
|
return __vfscanf_internal (stdin, format, args, 0);
|
||||||
}
|
}
|
||||||
ldbl_weak_alias (_IO_vscanf, vscanf)
|
ldbl_weak_alias (_IO_vscanf, vscanf)
|
||||||
|
@ -35,6 +35,6 @@
|
|||||||
int
|
int
|
||||||
__vwscanf (const wchar_t *format, va_list args)
|
__vwscanf (const wchar_t *format, va_list args)
|
||||||
{
|
{
|
||||||
return __vfwscanf_internal (_IO_stdin, format, args, 0);
|
return __vfwscanf_internal (stdin, format, args, 0);
|
||||||
}
|
}
|
||||||
ldbl_strong_alias (__vwscanf, vwscanf)
|
ldbl_strong_alias (__vwscanf, vwscanf)
|
||||||
|
Reference in New Issue
Block a user