This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] Use C99-compliant scanf under _GNU_SOURCE.
- From: Rical Jasan <ricaljasan at pacific dot net>
- To: Zack Weinberg <zackw at panix dot com>
- Cc: libc-alpha at sourceware dot org, joseph at codesourcery dot com, schwab at suse dot de
- Date: Mon, 12 Feb 2018 04:53:42 -0800
- Subject: Re: [PATCH] Use C99-compliant scanf under _GNU_SOURCE.
- Authentication-results: sourceware.org; auth=none
- References: <20180210181736.11570-1-zackw@panix.com>
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