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:
		| @@ -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; | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user