newlib: libc: Fix crash on fprintf to a wide-oriented stream.

Previously, fprintf() on a wide-oriented stream crashes or outputs
garbage. This is because a narrow char string which can be odd bytes
in length is cast into a wide char string which should be even
bytes in length in __sprint_r/__sfputs_r based on the __SWID flag.
As a result, if the length is odd bytes, the reading buffer runs over
the buffer length, which causes a crash. If the length is even bytes,
garbage is printed.

With this patch, any output to the stream which is set to different
orientation fails with error just like glibc. Note that it behaves
differently from other libc implementations such as BSD, musl and
Solaris.

Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
This commit is contained in:
Takashi Yano 2023-10-06 00:04:49 +09:00
parent 7863c07a92
commit 3d94e07c49
19 changed files with 92 additions and 40 deletions

View File

@ -177,8 +177,10 @@ _fgetwc_r (struct _reent *ptr,
wint_t r;
_newlib_flockfile_start (fp);
ORIENT(fp, 1);
r = __fgetwc (ptr, fp);
if (ORIENT(fp, 1) != 1)
r = WEOF;
else
r = __fgetwc (ptr, fp);
_newlib_flockfile_end (fp);
return r;
}

View File

@ -33,7 +33,8 @@ wint_t
_fgetwc_unlocked_r (struct _reent *ptr,
register FILE *fp)
{
ORIENT(fp, 1);
if (ORIENT(fp, 1) != 1)
return WEOF;
return __fgetwc (ptr, fp);
}

View File

@ -110,7 +110,8 @@ _fgetws_r (struct _reent *ptr,
unsigned char *nl;
_newlib_flockfile_start (fp);
ORIENT (fp, 1);
if (ORIENT (fp, 1) != 1)
goto error;
if (n <= 0)
{

View File

@ -103,8 +103,10 @@ _fputs_r (struct _reent * ptr,
CHECK_INIT(ptr, fp);
_newlib_flockfile_start (fp);
ORIENT (fp, -1);
result = __sfvwrite_r (ptr, fp, &uio);
if (ORIENT (fp, -1) != -1)
result = EOF;
else
result = __sfvwrite_r (ptr, fp, &uio);
_newlib_flockfile_end (fp);
return result;
#else
@ -113,7 +115,8 @@ _fputs_r (struct _reent * ptr,
CHECK_INIT(ptr, fp);
_newlib_flockfile_start (fp);
ORIENT (fp, -1);
if (ORIENT (fp, -1) != -1)
goto error;
/* Make sure we can write. */
if (cantwrite (ptr, fp))
goto error;

View File

@ -169,8 +169,10 @@ _fputwc_r (struct _reent *ptr,
wint_t r;
_newlib_flockfile_start (fp);
ORIENT(fp, 1);
r = __fputwc(ptr, wc, fp);
if (ORIENT(fp, 1) != 1)
r = WEOF;
else
r = __fputwc(ptr, wc, fp);
_newlib_flockfile_end (fp);
return r;
}

View File

@ -34,7 +34,8 @@ _fputwc_unlocked_r (struct _reent *ptr,
wchar_t wc,
FILE *fp)
{
ORIENT(fp, 1);
if (ORIENT(fp, 1) != 1)
return WEOF;
return __fputwc(ptr, wc, fp);
}

View File

@ -105,7 +105,8 @@ _fputws_r (struct _reent *ptr,
struct __siov iov;
_newlib_flockfile_start (fp);
ORIENT (fp, 1);
if (ORIENT (fp, 1) != 1)
goto error;
if (cantwrite (ptr, fp) != 0)
goto error;
uio.uio_iov = &iov;
@ -129,7 +130,8 @@ error:
return (-1);
#else
_newlib_flockfile_start (fp);
ORIENT (fp, 1);
if (ORIENT (fp, 1) != 1)
goto error;
if (cantwrite (ptr, fp) != 0)
goto error;

View File

@ -158,7 +158,11 @@ _fread_r (struct _reent * ptr,
CHECK_INIT(ptr, fp);
_newlib_flockfile_start (fp);
ORIENT (fp, -1);
if (ORIENT (fp, -1) != -1)
{
count = 0;
goto ret;
}
if (fp->_r < 0)
fp->_r = 0;
total = resid;
@ -252,6 +256,7 @@ _fread_r (struct _reent * ptr,
return crlf_r(ptr, fp, buf, total, 0) / size;
}
#endif
ret:
_newlib_flockfile_end (fp);
return count;
}

View File

@ -133,7 +133,11 @@ _fwrite_r (struct _reent * ptr,
CHECK_INIT(ptr, fp);
_newlib_flockfile_start (fp);
ORIENT (fp, -1);
if (ORIENT (fp, -1) != -1)
{
_newlib_flockfile_exit (fp);
return 0;
}
if (__sfvwrite_r (ptr, fp, &uio) == 0)
{
_newlib_flockfile_exit (fp);
@ -148,7 +152,8 @@ _fwrite_r (struct _reent * ptr,
CHECK_INIT (ptr, fp);
_newlib_flockfile_start (fp);
ORIENT (fp, -1);
if (ORIENT (fp, -1) != -1)
goto ret;
/* Make sure we can write. */
if (cantwrite (ptr, fp))
goto ret;

View File

@ -231,21 +231,24 @@ extern _READ_WRITE_RETURN_TYPE __swrite64 (struct _reent *, void *,
* Set the orientation for a stream. If o > 0, the stream has wide-
* orientation. If o < 0, the stream has byte-orientation.
*/
#define ORIENT(fp,ori) \
do \
{ \
if (!((fp)->_flags & __SORD)) \
{ \
(fp)->_flags |= __SORD; \
if (ori > 0) \
(fp)->_flags2 |= __SWID; \
else \
(fp)->_flags2 &= ~__SWID; \
} \
} \
while (0)
#define ORIENT(fp,ori) \
( \
( \
((fp)->_flags & __SORD) ? \
0 \
: \
( \
((fp)->_flags |= __SORD), \
(ori > 0) ? \
((fp)->_flags2 |= __SWID) \
: \
((fp)->_flags2 &= ~__SWID) \
) \
), \
((fp)->_flags2 & __SWID) ? 1 : -1 \
)
#else
#define ORIENT(fp,ori)
#define ORIENT(fp,ori) (-1)
#endif
/* WARNING: _dcvt is defined in the stdlib directory, not here! */

View File

@ -84,6 +84,8 @@ _putc_r (struct _reent *ptr,
{
int result;
CHECK_INIT (ptr, fp);
if (ORIENT (fp, -1) != -1)
return EOF;
_newlib_flockfile_start (fp);
result = __sputc_r (ptr, c, fp);
_newlib_flockfile_end (fp);
@ -100,6 +102,8 @@ putc (int c,
struct _reent *reent = _REENT;
CHECK_INIT (reent, fp);
if (ORIENT (fp, -1) != -1)
return EOF;
_newlib_flockfile_start (fp);
result = __sputc_r (reent, c, fp);
_newlib_flockfile_end (fp);

View File

@ -87,8 +87,10 @@ _puts_r (struct _reent *ptr,
fp = _stdout_r (ptr);
CHECK_INIT (ptr, fp);
_newlib_flockfile_start (fp);
ORIENT (fp, -1);
result = (__sfvwrite_r (ptr, fp, &uio) ? EOF : '\n');
if (ORIENT (fp, -1) != -1)
result = EOF;
else
result = (__sfvwrite_r (ptr, fp, &uio) ? EOF : '\n');
_newlib_flockfile_end (fp);
return result;
#else
@ -100,7 +102,8 @@ _puts_r (struct _reent *ptr,
fp = _stdout_r (ptr);
CHECK_INIT (ptr, fp);
_newlib_flockfile_start (fp);
ORIENT (fp, -1);
if (ORIENT (fp, -1) != -1)
goto err;
/* Make sure we can write. */
if (cantwrite (ptr, fp))
goto err;

View File

@ -43,7 +43,8 @@ __srefill_r (struct _reent * ptr,
CHECK_INIT (ptr, fp);
ORIENT (fp, -1);
if (ORIENT (fp, -1) != -1)
return EOF;
fp->_r = 0; /* largely a convenience for callers */

View File

@ -125,7 +125,11 @@ _ungetc_r (struct _reent *rptr,
_newlib_flockfile_start (fp);
ORIENT (fp, -1);
if (ORIENT (fp, -1) != -1)
{
_newlib_flockfile_exit (fp);
return EOF;
}
/* After ungetc, we won't be at eof anymore */
fp->_flags &= ~__SEOF;

View File

@ -82,8 +82,9 @@ _ungetwc_r (struct _reent *ptr,
size_t len;
_newlib_flockfile_start (fp);
ORIENT (fp, 1);
if (wc == WEOF)
if (ORIENT (fp, 1) != 1)
wc = WEOF;
else if (wc == WEOF)
wc = WEOF;
else if ((len = _wcrtomb_r(ptr, buf, wc, &fp->_mbstate)) == (size_t)-1)
{

View File

@ -845,7 +845,10 @@ _VFPRINTF_R (struct _reent *data,
CHECK_INIT (data, fp);
_newlib_flockfile_start (fp);
ORIENT(fp, -1);
if (ORIENT(fp, -1) != -1) {
_newlib_flockfile_exit (fp);
return (EOF);
}
/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
if (cantwrite (data, fp)) {

View File

@ -589,7 +589,11 @@ __SVFSCANF_R (struct _reent *rptr,
_newlib_flockfile_start (fp);
ORIENT (fp, -1);
if (ORIENT (fp, -1) != -1)
{
nassigned = EOF;
goto all_done;
}
nassigned = 0;
nread = 0;

View File

@ -588,7 +588,10 @@ _VFWPRINTF_R (struct _reent *data,
CHECK_INIT (data, fp);
_newlib_flockfile_start (fp);
ORIENT(fp, 1);
if (ORIENT(fp, 1) != 1) {
_newlib_flockfile_exit (fp);
return (EOF);
}
/* sorry, fwprintf(read_only_file, "") returns EOF, not 0 */
if (cantwrite (data, fp)) {

View File

@ -516,7 +516,11 @@ __SVFWSCANF_R (struct _reent *rptr,
_newlib_flockfile_start (fp);
ORIENT (fp, 1);
if (ORIENT (fp, 1) != 1)
{
nassigned = EOF;
goto all_done;
}
nassigned = 0;
nread = 0;