mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00: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:
parent
c70824b9a4
commit
ee9941f94e
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>
|
||||
|
||||
[BZ #14829]
|
||||
|
@ -37,8 +37,8 @@ __gets_chk (char *buf, size_t size)
|
||||
if (size == 0)
|
||||
__chk_fail ();
|
||||
|
||||
_IO_acquire_lock (_IO_stdin);
|
||||
ch = _IO_getc_unlocked (_IO_stdin);
|
||||
_IO_acquire_lock (stdin);
|
||||
ch = _IO_getc_unlocked (stdin);
|
||||
if (ch == EOF)
|
||||
{
|
||||
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
|
||||
non-blocking mode. The error flag doesn't mean much in this
|
||||
case. We return an error only when there is a new error. */
|
||||
int old_error = _IO_stdin->_flags & _IO_ERR_SEEN;
|
||||
_IO_stdin->_flags &= ~_IO_ERR_SEEN;
|
||||
int old_error = stdin->_flags & _IO_ERR_SEEN;
|
||||
stdin->_flags &= ~_IO_ERR_SEEN;
|
||||
buf[0] = (char) ch;
|
||||
count = _IO_getline (_IO_stdin, buf + 1, size - 1, '\n', 0) + 1;
|
||||
if (_IO_stdin->_flags & _IO_ERR_SEEN)
|
||||
count = _IO_getline (stdin, buf + 1, size - 1, '\n', 0) + 1;
|
||||
if (stdin->_flags & _IO_ERR_SEEN)
|
||||
{
|
||||
retval = NULL;
|
||||
goto unlock_return;
|
||||
}
|
||||
else
|
||||
_IO_stdin->_flags |= old_error;
|
||||
stdin->_flags |= old_error;
|
||||
}
|
||||
if (count >= size)
|
||||
__chk_fail ();
|
||||
buf[count] = 0;
|
||||
retval = buf;
|
||||
unlock_return:
|
||||
_IO_release_lock (_IO_stdin);
|
||||
_IO_release_lock (stdin);
|
||||
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-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
|
||||
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
|
||||
|
||||
|
@ -33,11 +33,11 @@ int
|
||||
getchar (void)
|
||||
{
|
||||
int result;
|
||||
if (!_IO_need_lock (_IO_stdin))
|
||||
return _IO_getc_unlocked (_IO_stdin);
|
||||
_IO_acquire_lock (_IO_stdin);
|
||||
result = _IO_getc_unlocked (_IO_stdin);
|
||||
_IO_release_lock (_IO_stdin);
|
||||
if (!_IO_need_lock (stdin))
|
||||
return _IO_getc_unlocked (stdin);
|
||||
_IO_acquire_lock (stdin);
|
||||
result = _IO_getc_unlocked (stdin);
|
||||
_IO_release_lock (stdin);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -32,5 +32,5 @@
|
||||
int
|
||||
getchar_unlocked (void)
|
||||
{
|
||||
return _IO_getc_unlocked (_IO_stdin);
|
||||
return _IO_getc_unlocked (stdin);
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ wint_t
|
||||
getwchar (void)
|
||||
{
|
||||
wint_t result;
|
||||
_IO_acquire_lock (_IO_stdin);
|
||||
result = _IO_getwc_unlocked (_IO_stdin);
|
||||
_IO_release_lock (_IO_stdin);
|
||||
_IO_acquire_lock (stdin);
|
||||
result = _IO_getwc_unlocked (stdin);
|
||||
_IO_release_lock (stdin);
|
||||
return result;
|
||||
}
|
||||
|
@ -32,5 +32,5 @@
|
||||
wint_t
|
||||
getwchar_unlocked (void)
|
||||
{
|
||||
return _IO_getwc_unlocked (_IO_stdin);
|
||||
return _IO_getwc_unlocked (stdin);
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ _IO_gets (char *buf)
|
||||
int ch;
|
||||
char *retval;
|
||||
|
||||
_IO_acquire_lock (_IO_stdin);
|
||||
ch = _IO_getc_unlocked (_IO_stdin);
|
||||
_IO_acquire_lock (stdin);
|
||||
ch = _IO_getc_unlocked (stdin);
|
||||
if (ch == EOF)
|
||||
{
|
||||
retval = NULL;
|
||||
@ -48,22 +48,22 @@ _IO_gets (char *buf)
|
||||
/* This is very tricky since a file descriptor may be in the
|
||||
non-blocking mode. The error flag doesn't mean much in this
|
||||
case. We return an error only when there is a new error. */
|
||||
int old_error = _IO_stdin->_flags & _IO_ERR_SEEN;
|
||||
_IO_stdin->_flags &= ~_IO_ERR_SEEN;
|
||||
int old_error = stdin->_flags & _IO_ERR_SEEN;
|
||||
stdin->_flags &= ~_IO_ERR_SEEN;
|
||||
buf[0] = (char) ch;
|
||||
count = _IO_getline (_IO_stdin, buf + 1, INT_MAX, '\n', 0) + 1;
|
||||
if (_IO_stdin->_flags & _IO_ERR_SEEN)
|
||||
count = _IO_getline (stdin, buf + 1, INT_MAX, '\n', 0) + 1;
|
||||
if (stdin->_flags & _IO_ERR_SEEN)
|
||||
{
|
||||
retval = NULL;
|
||||
goto unlock_return;
|
||||
}
|
||||
else
|
||||
_IO_stdin->_flags |= old_error;
|
||||
stdin->_flags |= old_error;
|
||||
}
|
||||
buf[count] = 0;
|
||||
retval = buf;
|
||||
unlock_return:
|
||||
_IO_release_lock (_IO_stdin);
|
||||
_IO_release_lock (stdin);
|
||||
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
|
||||
_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)
|
||||
|
@ -35,6 +35,6 @@
|
||||
int
|
||||
__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)
|
||||
|
Loading…
Reference in New Issue
Block a user