This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Use C99-compliant scanf under _GNU_SOURCE.


On 02/10/2018 10:17 AM, Zack Weinberg wrote:
> The only difference between noncompliant and C99-compliant scanf is
> that the former accepts the archaic GNU extension '%as' (also %aS and
> %a[...]) meaning to allocate space for the input string with malloc.
> This extension conflicts with C99's use of %a as a format _type_
> meaning to read a floating-point number; POSIX.1-2001 standardized

POSIX.1-2008, from what I could tell (Issue 7 of IEEE 1003.1, if I'm
saying that right).  This happens a few times throughout.

> equivalent functionality using the modifier letter 'm' instead (%ms,
> %mS, %m[...]).
...
> diff --git a/NEWS b/NEWS
> index 60dd2f778d9..45465b785e3 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -28,6 +28,21 @@ Deprecated and removed features, and other changes affecting compatibility:
>     investigate using (f)getc_unlocked and (f)putc_unlocked, and, if
>     necessary, flockfile and funlockfile.
>  
> + * The scanf formats '%as', '%aS', and '%a[...]', meaning to read a string
> +   and allocate space for it using malloc, are no longer accepted in code
> +   compiled with _GNU_SOURCE.  They were already not accepted in code
> +   compiled in the default mode with modern compilers (e.g. GCC new enough
> +   to default to -std=gnu11, without _GNU_SOURCE).
> +
> +   Using 'a' as a modifier letter for 's'-type scanf formats is an archaic
> +   GNU extension that conflicts with C99's use of '%a' for floating-point
> +   numbers.  Equivalent functionality was standardized in POSIX.1-2001 using
> +   the letter 'm' instead; programs using '%as', '%aS', and '%a[...]' should
> +   change to '%ms', '%mS', and '%m[...]' respectively.  GCC's -Wformat
> +   warnings can detect most uses of the extension, as long as all functions
> +   that call vscanf, vfscanf, or vsscanf are annotated with
> +   __attribute__((format(scanf, ...))).
> +
>   * The macros 'major', 'minor', and 'makedev' are now only available from
>     the header <sys/sysmacros.h>; not from <sys/types.h> or various other
>     headers that happen to include <sys/types.h>.  These macros are rarely
> diff --git a/include/features.h b/include/features.h
> index 137a90b4055..e6b19c5789c 100644
> --- a/include/features.h
> +++ b/include/features.h
> @@ -140,6 +140,7 @@
>  #undef	__USE_FORTIFY_LEVEL
>  #undef	__KERNEL_STRICT_NAMES
>  #undef	__GLIBC_USE_DEPRECATED_GETS
> +#undef  __GLIBC_USE_DEPRECATED_SCANF

Should be a tab.

>  
>  /* Suppress kernel-name space pollution unless user expressedly asks
>     for it.  */
> @@ -401,6 +402,20 @@
>  # define __GLIBC_USE_DEPRECATED_GETS 1
>  #endif
>  
> +/* GNU formerly extended the 'scanf' functions with modified format
> +   specifiers %as, %aS, and %a[...] that allocate a buffer for the
> +   input using malloc.  This extension conflicts with ISO C99, which
> +   defines %a as a standalone format specifier that reads a
> +   floating-point number; moreover, POSIX.1-2001 provides the same
> +   functionality using the modifier letter 'm' instead (%ms, %mS,
> +   %m[...]).  We now follow C99 and POSIX unless an old, non-strict
> +   conformance level is specifically selected.  */
> +#if defined __USE_ISOC99 && (defined __USE_XOPEN2K || defined __STRICT_ANSI__)
> +# define __GLIBC_USE_DEPRECATED_SCANF 0
> +#else
> +# define __GLIBC_USE_DEPRECATED_SCANF 1
> +#endif
> +
>  /* Get definitions of __STDC_* predefined macros, if the compiler has
>     not preincluded this header automatically.  */
>  #include <stdc-predef.h>
> diff --git a/include/stdio.h b/include/stdio.h
> index 94bc2fdc7ef..d0e9343b2a9 100644
> --- a/include/stdio.h
> +++ b/include/stdio.h
> @@ -67,6 +67,7 @@ extern int __isoc99_vscanf (const char *__restrict __format,
>  extern int __isoc99_vsscanf (const char *__restrict __s,
>  			     const char *__restrict __format,
>  			     __gnuc_va_list __arg) __THROW;
> +libc_hidden_proto (__isoc99_sscanf)
>  libc_hidden_proto (__isoc99_vsscanf)
>  libc_hidden_proto (__isoc99_vfscanf)
>  
> @@ -154,7 +155,6 @@ libc_hidden_proto (__dprintf)
>  libc_hidden_proto (fprintf)
>  libc_hidden_proto (vfprintf)
>  libc_hidden_proto (sprintf)
> -libc_hidden_proto (sscanf)
>  libc_hidden_proto (fwrite)
>  libc_hidden_proto (perror)
>  libc_hidden_proto (remove)
> diff --git a/libio/bits/stdio-ldbl.h b/libio/bits/stdio-ldbl.h
> index 99d9bcc2334..ab55cbe7fb2 100644
> --- a/libio/bits/stdio-ldbl.h
> +++ b/libio/bits/stdio-ldbl.h
> @@ -26,9 +26,7 @@ __LDBL_REDIR_DECL (sprintf)
>  __LDBL_REDIR_DECL (vfprintf)
>  __LDBL_REDIR_DECL (vprintf)
>  __LDBL_REDIR_DECL (vsprintf)
> -#if defined __USE_ISOC99 && !defined __USE_GNU \
> -    && !defined __REDIRECT \
> -    && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
> +#if !__GLIBC_USE (DEPRECATED_SCANF) && defined __REDIRECT
>  __LDBL_REDIR1_DECL (fscanf, __nldbl___isoc99_fscanf)
>  __LDBL_REDIR1_DECL (scanf, __nldbl___isoc99_scanf)
>  __LDBL_REDIR1_DECL (sscanf, __nldbl___isoc99_sscanf)
> @@ -44,8 +42,7 @@ __LDBL_REDIR_DECL (vsnprintf)
>  #endif
>  
>  #ifdef	__USE_ISOC99
> -# if !defined __USE_GNU && !defined __REDIRECT \
> -     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
> +#if !__GLIBC_USE (DEPRECATED_SCANF) && defined __REDIRECT

This #if should still be indented one space, I believe.  You might be
able to get rid of the outer "#ifdef __USE_ISOC99" though, since it only
wraps this this one block.

>  __LDBL_REDIR1_DECL (vfscanf, __nldbl___isoc99_vfscanf)
>  __LDBL_REDIR1_DECL (vscanf, __nldbl___isoc99_vscanf)
>  __LDBL_REDIR1_DECL (vsscanf, __nldbl___isoc99_vsscanf)
> diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
> index b5514fc74ea..e072258ba30 100644
> --- a/libio/iovsscanf.c
> +++ b/libio/iovsscanf.c
> @@ -24,6 +24,11 @@
>     This exception applies to code released by its copyright holders
>     in files containing the exception.  */
>  
> +/* This file defines one of the deprecated scanf variants.  */
> +#include <features.h>
> +#undef __GLIBC_USE_DEPRECATED_SCANF
> +#define __GLIBC_USE_DEPRECATED_SCANF 1
> +
>  #include "libioP.h"
>  #include "strfile.h"
>  
> diff --git a/libio/stdio.h b/libio/stdio.h
> index 731f8e56f4c..a04539639db 100644
> --- a/libio/stdio.h
> +++ b/libio/stdio.h
> @@ -387,13 +387,11 @@ extern int scanf (const char *__restrict __format, ...) __wur;
>  extern int sscanf (const char *__restrict __s,
>  		   const char *__restrict __format, ...) __THROW;
>  
> -#if defined __USE_ISOC99 && !defined __USE_GNU \
> -    && (!defined __LDBL_COMPAT || !defined __REDIRECT) \
> -    && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
> -# ifdef __REDIRECT
> -/* For strict ISO C99 or POSIX compliance disallow %as, %aS and %a[
> -   GNU extension which conflicts with valid %a followed by letter
> -   s, S or [.  */
> +/* For historical reasons, the C99-compliant versions of the scanf
> +   functions are at alternative names.  When __LDBL_COMPAT is in
> +   effect, this is handled in bits/stdio-ldbl.h.  */
> +#if !__GLIBC_USE (DEPRECATED_SCANF)
> +# if defined __REDIRECT && !defined __LDBL_COMPAT
>  extern int __REDIRECT (fscanf, (FILE *__restrict __stream,
>  				const char *__restrict __format, ...),
>  		       __isoc99_fscanf) __wur;
> @@ -402,7 +400,7 @@ extern int __REDIRECT (scanf, (const char *__restrict __format, ...),
>  extern int __REDIRECT_NTH (sscanf, (const char *__restrict __s,
>  				    const char *__restrict __format, ...),
>  			   __isoc99_sscanf);
> -# else
> +# elif !defined __REDIRECT

Should this still include the "!defined __LDBL_COMPAT"?  Or maybe put
that on the line with DEPRECATED_SCANF, so it also wraps the __REDIRECT
if-else?

>  extern int __isoc99_fscanf (FILE *__restrict __stream,
>  			    const char *__restrict __format, ...) __wur;
>  extern int __isoc99_scanf (const char *__restrict __format, ...) __wur;
> @@ -435,13 +433,9 @@ extern int vsscanf (const char *__restrict __s,
>  		    const char *__restrict __format, __gnuc_va_list __arg)
>       __THROW __attribute__ ((__format__ (__scanf__, 2, 0)));
>  
> -# if !defined __USE_GNU \
> -     && (!defined __LDBL_COMPAT || !defined __REDIRECT) \
> -     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
> -#  ifdef __REDIRECT
> -/* For strict ISO C99 or POSIX compliance disallow %as, %aS and %a[
> -   GNU extension which conflicts with valid %a followed by letter
> -   s, S or [.  */
> +/* Same redirection as above for the v*scanf family.  */
> +# if !__GLIBC_USE (DEPRECATED_SCANF)
> +#  if defined __REDIRECT && !defined __LDBL_COMPAT
>  extern int __REDIRECT (vfscanf,
>  		       (FILE *__restrict __s,
>  			const char *__restrict __format, __gnuc_va_list __arg),
> @@ -455,7 +449,7 @@ extern int __REDIRECT_NTH (vsscanf,
>  			    const char *__restrict __format,
>  			    __gnuc_va_list __arg), __isoc99_vsscanf)
>       __attribute__ ((__format__ (__scanf__, 2, 0)));
> -#  else
> +#  elif !defined __REDIRECT
>  extern int __isoc99_vfscanf (FILE *__restrict __s,
>  			     const char *__restrict __format,
>  			     __gnuc_va_list __arg) __wur;

Rical


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]