newlib: vf[w]scanf: add validity checks

POSIX requires that directive characters appear in a certain sequence:

1. '%' or '%<n>$'
2. optional '*'
3. optional field width digits
4. optional 'm' (not yet implemented)
5. optional length modifier ('l', 'L', 'll', 'h', 'hh', 'j', 't', 'z')
6. conversion specifier ('d', 's', etc)

Add a few basic validity checks to that effect, otherwise reject
directive as match failure.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2017-11-30 11:55:27 +01:00
parent 31f11d0572
commit 0fd2c9bd12
2 changed files with 37 additions and 0 deletions

View File

@ -564,9 +564,14 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
continue; continue;
case '*': case '*':
if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
|| width)
goto match_failure;
flags |= SUPPRESS; flags |= SUPPRESS;
goto again; goto again;
case 'l': case 'l':
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG #if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
if (*fmt == 'l') /* Check for 'll' = long long (SUSv3) */ if (*fmt == 'l') /* Check for 'll' = long long (SUSv3) */
{ {
@ -578,9 +583,13 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
flags |= LONG; flags |= LONG;
goto again; goto again;
case 'L': case 'L':
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
flags |= LONGDBL; flags |= LONGDBL;
goto again; goto again;
case 'h': case 'h':
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
#ifdef _WANT_IO_C99_FORMATS #ifdef _WANT_IO_C99_FORMATS
if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */ if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */
{ {
@ -593,12 +602,16 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
goto again; goto again;
#ifdef _WANT_IO_C99_FORMATS #ifdef _WANT_IO_C99_FORMATS
case 'j': /* intmax_t */ case 'j': /* intmax_t */
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
if (sizeof (intmax_t) == sizeof (long)) if (sizeof (intmax_t) == sizeof (long))
flags |= LONG; flags |= LONG;
else else
flags |= LONGDBL; flags |= LONGDBL;
goto again; goto again;
case 't': /* ptrdiff_t */ case 't': /* ptrdiff_t */
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
if (sizeof (ptrdiff_t) < sizeof (int)) if (sizeof (ptrdiff_t) < sizeof (int))
/* POSIX states ptrdiff_t is 16 or more bits, as /* POSIX states ptrdiff_t is 16 or more bits, as
is short. */ is short. */
@ -615,6 +628,8 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
flags |= LONGDBL; flags |= LONGDBL;
goto again; goto again;
case 'z': /* size_t */ case 'z': /* size_t */
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
if (sizeof (size_t) < sizeof (int)) if (sizeof (size_t) < sizeof (int))
/* POSIX states size_t is 16 or more bits, as is short. */ /* POSIX states size_t is 16 or more bits, as is short. */
flags |= SHORT; flags |= SHORT;
@ -641,11 +656,15 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
case '7': case '7':
case '8': case '8':
case '9': case '9':
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
width = width * 10 + c - '0'; width = width * 10 + c - '0';
goto again; goto again;
#ifndef _NO_POS_ARGS #ifndef _NO_POS_ARGS
case '$': case '$':
if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
goto match_failure;
if (width <= MAX_POS_ARGS) if (width <= MAX_POS_ARGS)
{ {
N = width - 1; N = width - 1;

View File

@ -518,9 +518,13 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
continue; continue;
case L'*': case L'*':
if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
|| width)
flags |= SUPPRESS; flags |= SUPPRESS;
goto again; goto again;
case L'l': case L'l':
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG #if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
if (*fmt == L'l') /* Check for 'll' = long long (SUSv3) */ if (*fmt == L'l') /* Check for 'll' = long long (SUSv3) */
{ {
@ -532,10 +536,14 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
flags |= LONG; flags |= LONG;
goto again; goto again;
case L'L': case L'L':
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
flags |= LONGDBL; flags |= LONGDBL;
goto again; goto again;
case L'h': case L'h':
#ifdef _WANT_IO_C99_FORMATS #ifdef _WANT_IO_C99_FORMATS
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */ if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */
{ {
++fmt; ++fmt;
@ -547,12 +555,16 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
goto again; goto again;
#ifdef _WANT_IO_C99_FORMATS #ifdef _WANT_IO_C99_FORMATS
case L'j': /* intmax_t */ case L'j': /* intmax_t */
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
if (sizeof (intmax_t) == sizeof (long)) if (sizeof (intmax_t) == sizeof (long))
flags |= LONG; flags |= LONG;
else else
flags |= LONGDBL; flags |= LONGDBL;
goto again; goto again;
case L't': /* ptrdiff_t */ case L't': /* ptrdiff_t */
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
if (sizeof (ptrdiff_t) < sizeof (int)) if (sizeof (ptrdiff_t) < sizeof (int))
/* POSIX states ptrdiff_t is 16 or more bits, as /* POSIX states ptrdiff_t is 16 or more bits, as
is short. */ is short. */
@ -569,6 +581,8 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
flags |= LONGDBL; flags |= LONGDBL;
goto again; goto again;
case L'z': /* size_t */ case L'z': /* size_t */
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
if (sizeof (size_t) < sizeof (int)) if (sizeof (size_t) < sizeof (int))
/* POSIX states size_t is 16 or more bits, as is short. */ /* POSIX states size_t is 16 or more bits, as is short. */
flags |= SHORT; flags |= SHORT;
@ -595,11 +609,15 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
case L'7': case L'7':
case L'8': case L'8':
case L'9': case L'9':
if (flags & (CHAR | SHORT | LONG | LONGDBL))
goto match_failure;
width = width * 10 + c - L'0'; width = width * 10 + c - L'0';
goto again; goto again;
#ifndef _NO_POS_ARGS #ifndef _NO_POS_ARGS
case L'$': case L'$':
if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
goto match_failure;
if (width <= MAX_POS_ARGS) if (width <= MAX_POS_ARGS)
{ {
N = width - 1; N = width - 1;