This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

[PATCH] Add support for scanf ("%ms", ...) etc. for -Wformat


Hi!

glibc 2.7+ will support 'm' assignment-allocation modifier for *scanf.
It is very similar to the 'a' modifier, which was a GNU extension,
with the major difference that it doesn't colide with ISO C99
a format character, also some smaller details related to error handling
when malloc/realloc fails and also documentation which says it must appear
between the (optional) width and (optional) length modifiers.
Although glibc is more lax in this case and handles both 'm' and 'a'
modifiers among length modifiers so both %mls and %lms will be handled
by glibc, IMHO it is much better if GCC tries to enforce the upcoming
POSIX definition, see
http://www.opengroup.org/austin/aardvark/latest/xshbug2.txt
in ERN132 (which has been changed slightly afterwards, in the error
handling case and also that %mc, %mlc and %mC is now allowed as well).
AFAIK the choice of the 'm' modifier has been cleared with ISO C WG,
so the %as clash shouldn't repeat again in this case.

Given the unfortunate state of the %as/%aS/%a[ extension it is IMHO
preferrable if applications using it start using %ms/%mS/%m[ instead
as soon as possible and for that no GCC complaints about such format
specifiers are very desirable.
Ok for trunk?

2007-09-16  Jakub Jelinek  <jakub@redhat.com>

	* c-format.c (scanf_flag_specs): Add 'm'.
	(scanf_flag_pairs): Add 'a', 'm' pair.
	(scan_char_table): Allow 'm' modifier for c, s, [, C and S.
	(check_format_info_main): Rename aflag to amflag.  Handle 'm' scanf
	modifier after width and before length modifiers.

	* gcc.dg/format/c90-scanf-5.c: New test.
	* gcc.dg/format/c99-scanf-4.c: New test.
	* gcc.dg/format/ext-7.c: New test.
	* gcc.dg/format/ext-8.c: New test.

--- gcc/c-format.c.jj	2007-09-11 12:43:28.000000000 +0200
+++ gcc/c-format.c	2007-09-16 21:19:51.000000000 +0200
@@ -437,6 +437,7 @@ static const format_flag_spec scanf_flag
 {
   { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
   { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'm',  0, 0, N_("'m' flag"),               N_("the 'm' scanf flag"),                       STD_EXT },
   { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
   { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
   { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
@@ -448,6 +449,7 @@ static const format_flag_spec scanf_flag
 static const format_flag_pair scanf_flag_pairs[] =
 {
   { '*', 'L', 0, 0 },
+  { 'a', 'm', 0, 0 },
   { 0, 0, 0, 0 }
 };
 
@@ -663,17 +665,17 @@ static const format_char_info scan_char_
   { "u",     1, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM, BADLEN,  BADLEN,  BADLEN }, "*w'I", "W",   NULL },
   { "oxX",   1, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
   { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "*w'",  "W",   NULL },
-  { "c",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
-  { "s",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
-  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*mw",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*amw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*amw",  "cW[", NULL },
   { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
   { "n",     1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
   /* C99 conversion specifiers.  */
   { "F",   1, STD_C99, { T99_F,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "*w'",  "W",   NULL },
   { "aA",   1, STD_C99, { T99_F,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'",  "W",   NULL },
   /* X/Open conversion specifiers.  */
-  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
-  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*mw",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*amw",  "W",   NULL },
   { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
 };
 
@@ -1482,7 +1484,7 @@ check_format_info_main (format_check_res
       const format_length_info *fli = NULL;
       const format_char_info *fci = NULL;
       char flag_chars[256];
-      int aflag = 0;
+      int amflag = 0;
       const char *format_start = format_chars;
       if (*format_chars == 0)
 	{
@@ -1741,6 +1743,16 @@ check_format_info_main (format_check_res
 	    }
 	}
 
+      if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) && *format_chars == 'm')
+	{
+	  /* 'm' assignment allocation character.  Must be in between optional
+	     width and optional length modifiers.  */
+	  i = strlen (flag_chars);
+	  flag_chars[i++] = 'm';
+	  flag_chars[i] = 0;
+	  format_chars++;
+	}
+
       /* Read any length modifier, if this kind of format has them.  */
       fli = fki->length_char_specs;
       length_chars = NULL;
@@ -1891,8 +1903,9 @@ check_format_info_main (format_check_res
       }
 
       if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE)
-	  && strchr (flag_chars, 'a') != 0)
-	aflag = 1;
+	  && (strchr (flag_chars, 'a') != 0
+	      || strchr (flag_chars, 'm') != 0))
+	amflag = 1;
 
       if (fki->suppression_char
 	  && strchr (flag_chars, fki->suppression_char) != 0)
@@ -2064,13 +2077,13 @@ check_format_info_main (format_check_res
 
 	      wanted_type_ptr->wanted_type = wanted_type;
 	      wanted_type_ptr->wanted_type_name = wanted_type_name;
-	      wanted_type_ptr->pointer_count = fci->pointer_count + aflag;
+	      wanted_type_ptr->pointer_count = fci->pointer_count + amflag;
 	      wanted_type_ptr->char_lenient_flag = 0;
 	      if (strchr (fci->flags2, 'c') != 0)
 		wanted_type_ptr->char_lenient_flag = 1;
 	      wanted_type_ptr->writing_in_flag = 0;
 	      wanted_type_ptr->reading_from_flag = 0;
-	      if (aflag)
+	      if (amflag)
 		wanted_type_ptr->writing_in_flag = 1;
 	      else
 		{
--- gcc/testsuite/gcc.dg/format/c90-scanf-5.c.jj	2007-09-16 21:23:14.000000000 +0200
+++ gcc/testsuite/gcc.dg/format/c90-scanf-5.c	2007-09-16 21:29:52.000000000 +0200
@@ -0,0 +1,19 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX extension.  */
+  scanf ("%ms", sp); /* { dg-warning "C" "%ms" } */
+  scanf ("%mS", lsp); /* { dg-warning "C" "%mS" } */
+  scanf ("%mls", lsp); /* { dg-warning "C" "%mls" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "C" "%m[]" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "C" "%ml[]" } */
+}
--- gcc/testsuite/gcc.dg/format/c99-scanf-4.c.jj	2007-09-16 21:25:53.000000000 +0200
+++ gcc/testsuite/gcc.dg/format/c99-scanf-4.c	2007-09-16 21:30:00.000000000 +0200
@@ -0,0 +1,19 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX extension.  */
+  scanf ("%ms", sp); /* { dg-warning "C" "%ms" } */
+  scanf ("%mS", lsp); /* { dg-warning "C" "%mS" } */
+  scanf ("%mls", lsp); /* { dg-warning "C" "%mls" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "C" "%m[]" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "C" "%ml[]" } */
+}
--- gcc/testsuite/gcc.dg/format/ext-7.c.jj	2007-09-16 20:37:42.000000000 +0200
+++ gcc/testsuite/gcc.dg/format/ext-7.c	2007-09-16 21:30:51.000000000 +0200
@@ -0,0 +1,85 @@
+/* Test for scanf formats.  %a and %m extensions.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89 -Wformat" } */
+
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp, int *ip, float *fp, void **pp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.  Followed by other characters, %a is not treated
+     specially.
+  */
+  scanf ("%as", sp);
+  scanf ("%aS", lsp);
+  scanf ("%las", lsp);
+  scanf ("%a[bcd]", sp);
+  scanf ("%la[bcd]", lsp);
+  scanf ("%*as");
+  scanf ("%*aS");
+  scanf ("%*las");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*a[bcd]");
+  scanf ("%*la[bcd]");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%10as", sp);
+  scanf ("%5aS", lsp);
+  scanf ("%9las", lsp);
+  scanf ("%25a[bcd]", sp);
+  scanf ("%48la[bcd]", lsp);
+  scanf ("%*10as");
+  scanf ("%*5aS");
+  scanf ("%*9las");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*25a[bcd]");
+  scanf ("%*48la[bcd]"); /* { dg-warning "assignment suppression and length modifier" } */
+
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX extension.  */
+  scanf ("%ms", sp);
+  scanf ("%mS", lsp);
+  scanf ("%mls", lsp);
+  scanf ("%m[bcd]", sp);
+  scanf ("%ml[bcd]", lsp);
+  scanf ("%mc", sp);
+  scanf ("%mlc", lsp);
+  scanf ("%mC", lsp);
+  scanf ("%*ms");
+  scanf ("%*mS");
+  scanf ("%*mls");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*m[bcd]");
+  scanf ("%*ml[bcd]");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*mc");
+  scanf ("%*mlc");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*mC");
+  scanf ("%10ms", sp);
+  scanf ("%5mS", lsp);
+  scanf ("%9mls", lsp);
+  scanf ("%25m[bcd]", sp);
+  scanf ("%41ml[bcd]", lsp);
+  scanf ("%131mc", sp);
+  scanf ("%27mlc", lsp);
+  scanf ("%2mC", lsp);
+  scanf ("%*10ms");
+  scanf ("%*5mS");
+  scanf ("%*9mls");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*25m[bcd]");
+  scanf ("%*41ml[bcd]"); /* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*131mc");
+  scanf ("%*27mlc");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*2mC");
+
+  scanf ("%md", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%mi", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%mo", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%mu", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%mx", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%me", fp);	/* { dg-warning "flag used with" } */
+  scanf ("%mf", fp);	/* { dg-warning "flag used with" } */
+  scanf ("%mg", fp);	/* { dg-warning "flag used with" } */
+  scanf ("%mp", pp);	/* { dg-warning "flag used with" } */
+
+  scanf ("%mas", sp);	/* { dg-warning "flag together" } */
+  scanf ("%mlas", lsp);	/* { dg-warning "flag together" } */
+  scanf ("%maS", lsp);	/* { dg-warning "flag together" } */
+  scanf ("%ma[bcd]", sp);	/* { dg-warning "flag together" } */
+  scanf ("%mla[bcd]", lsp);	/* { dg-warning "flag together" } */
+}
--- gcc/testsuite/gcc.dg/format/ext-8.c.jj	2007-09-16 21:18:13.000000000 +0200
+++ gcc/testsuite/gcc.dg/format/ext-8.c	2007-09-16 21:28:56.000000000 +0200
@@ -0,0 +1,56 @@
+/* Test for scanf formats.  %m extensions.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp, int *ip, float *fp, void **pp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX extension.  */
+  scanf ("%ms", sp);
+  scanf ("%mS", lsp);
+  scanf ("%mls", lsp);
+  scanf ("%m[bcd]", sp);
+  scanf ("%ml[bcd]", lsp);
+  scanf ("%mc", sp);
+  scanf ("%mlc", lsp);
+  scanf ("%mC", lsp);
+  scanf ("%*ms");
+  scanf ("%*mS");
+  scanf ("%*mls");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*m[bcd]");
+  scanf ("%*ml[bcd]");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*mc");
+  scanf ("%*mlc");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*mC");
+  scanf ("%10ms", sp);
+  scanf ("%5mS", lsp);
+  scanf ("%9mls", lsp);
+  scanf ("%25m[bcd]", sp);
+  scanf ("%41ml[bcd]", lsp);
+  scanf ("%131mc", sp);
+  scanf ("%27mlc", lsp);
+  scanf ("%2mC", lsp);
+  scanf ("%*10ms");
+  scanf ("%*5mS");
+  scanf ("%*9mls");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*25m[bcd]");
+  scanf ("%*41ml[bcd]"); /* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*131mc");
+  scanf ("%*27mlc");	/* { dg-warning "assignment suppression and length modifier" } */
+  scanf ("%*2mC");
+
+  scanf ("%md", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%mi", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%mo", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%mu", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%mx", ip);	/* { dg-warning "flag used with" } */
+  scanf ("%ma", fp);	/* { dg-warning "flag used with" } */
+  scanf ("%mA", fp);	/* { dg-warning "flag used with" } */
+  scanf ("%me", fp);	/* { dg-warning "flag used with" } */
+  scanf ("%mf", fp);	/* { dg-warning "flag used with" } */
+  scanf ("%mg", fp);	/* { dg-warning "flag used with" } */
+  scanf ("%mp", pp);	/* { dg-warning "flag used with" } */
+}

	Jakub


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