Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2017-11-30 13:55:27 +0300
committerCorinna Vinschen <corinna@vinschen.de>2017-11-30 13:55:27 +0300
commit0fd2c9bd1290c84d2160191d105147bf75629411 (patch)
treea3d7d35438c6ee377ea4611f977cedbffd44eca4 /newlib/libc/stdio
parent31f11d0572495ed16f9fbdab9fefaeb64b665a79 (diff)
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>
Diffstat (limited to 'newlib/libc/stdio')
-rw-r--r--newlib/libc/stdio/vfscanf.c19
-rw-r--r--newlib/libc/stdio/vfwscanf.c18
2 files changed, 37 insertions, 0 deletions
diff --git a/newlib/libc/stdio/vfscanf.c b/newlib/libc/stdio/vfscanf.c
index a81ebd5b8..9d6f12404 100644
--- a/newlib/libc/stdio/vfscanf.c
+++ b/newlib/libc/stdio/vfscanf.c
@@ -564,9 +564,14 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
continue;
case '*':
+ if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
+ || width)
+ goto match_failure;
flags |= SUPPRESS;
goto again;
case 'l':
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
if (*fmt == 'l') /* Check for 'll' = long long (SUSv3) */
{
@@ -578,9 +583,13 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
flags |= LONG;
goto again;
case 'L':
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
flags |= LONGDBL;
goto again;
case 'h':
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
#ifdef _WANT_IO_C99_FORMATS
if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */
{
@@ -593,12 +602,16 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
goto again;
#ifdef _WANT_IO_C99_FORMATS
case 'j': /* intmax_t */
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
if (sizeof (intmax_t) == sizeof (long))
flags |= LONG;
else
flags |= LONGDBL;
goto again;
case 't': /* ptrdiff_t */
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
if (sizeof (ptrdiff_t) < sizeof (int))
/* POSIX states ptrdiff_t is 16 or more bits, as
is short. */
@@ -615,6 +628,8 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
flags |= LONGDBL;
goto again;
case 'z': /* size_t */
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
if (sizeof (size_t) < sizeof (int))
/* POSIX states size_t is 16 or more bits, as is short. */
flags |= SHORT;
@@ -641,11 +656,15 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
case '7':
case '8':
case '9':
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
width = width * 10 + c - '0';
goto again;
#ifndef _NO_POS_ARGS
case '$':
+ if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
+ goto match_failure;
if (width <= MAX_POS_ARGS)
{
N = width - 1;
diff --git a/newlib/libc/stdio/vfwscanf.c b/newlib/libc/stdio/vfwscanf.c
index 0d34fb1a1..54bbb09b0 100644
--- a/newlib/libc/stdio/vfwscanf.c
+++ b/newlib/libc/stdio/vfwscanf.c
@@ -518,9 +518,13 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
continue;
case L'*':
+ if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
+ || width)
flags |= SUPPRESS;
goto again;
case L'l':
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
#if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG
if (*fmt == L'l') /* Check for 'll' = long long (SUSv3) */
{
@@ -532,10 +536,14 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
flags |= LONG;
goto again;
case L'L':
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
flags |= LONGDBL;
goto again;
case L'h':
#ifdef _WANT_IO_C99_FORMATS
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */
{
++fmt;
@@ -547,12 +555,16 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
goto again;
#ifdef _WANT_IO_C99_FORMATS
case L'j': /* intmax_t */
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
if (sizeof (intmax_t) == sizeof (long))
flags |= LONG;
else
flags |= LONGDBL;
goto again;
case L't': /* ptrdiff_t */
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
if (sizeof (ptrdiff_t) < sizeof (int))
/* POSIX states ptrdiff_t is 16 or more bits, as
is short. */
@@ -569,6 +581,8 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
flags |= LONGDBL;
goto again;
case L'z': /* size_t */
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
if (sizeof (size_t) < sizeof (int))
/* POSIX states size_t is 16 or more bits, as is short. */
flags |= SHORT;
@@ -595,11 +609,15 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
case L'7':
case L'8':
case L'9':
+ if (flags & (CHAR | SHORT | LONG | LONGDBL))
+ goto match_failure;
width = width * 10 + c - L'0';
goto again;
#ifndef _NO_POS_ARGS
case L'$':
+ if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS))
+ goto match_failure;
if (width <= MAX_POS_ARGS)
{
N = width - 1;