m4-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

avoid undefined behavior in format(%c)


From: Eric Blake
Subject: avoid undefined behavior in format(%c)
Date: Mon, 09 Jul 2007 06:52:52 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070604 Thunderbird/2.0.0.4 Mnenhy/0.7.5.666

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I introduced a regression in 1.4.9b where format(%c,65) would call
printf("%*.*c",0,-1,'a') under the hood, but that is undefined in POSIX.
This is just a stop-gap measure so that I can release 1.4.10 without known
undefined behavior; I still intend to make 1.4.11 where the format builtin
has more capabilities bringing it more in line with printf(1), but want to
get a GPLv3 version out now rather than after completing that patch.

I'm applying this to both branch and head.  My goal is to get 1.4.10 out
by tomorrow.

2007-07-09  Eric Blake  <address@hidden>

        Avoid undefined behavior of %.*c in printf.
        * src/format.c (format): Special case %c.
        * TODO: Document that more remains to be done.
        * NEWS: Document the fix.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFGki+k84KuGfSFAYARAiJPAJwJMnYYR3/K6SpeKR5VMmetyBSjYwCgqqFU
97SHUuO1CrJlcNjXa4RQBwY=
=iTY5
-----END PGP SIGNATURE-----
Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.1.1.1.2.106
diff -u -p -r1.1.1.1.2.106 NEWS
--- NEWS        5 Jul 2007 03:53:05 -0000       1.1.1.1.2.106
+++ NEWS        9 Jul 2007 12:50:54 -0000
@@ -5,6 +5,11 @@ Foundation, Inc.
 Version 1.4.10 - ?? ??? 2007, by ????  (CVS version 1.4.9c)
 
 * Upgrade from GPL version 2 to GPL version 3 or later.
+* A number of portability improvements inherited from gnulib.
+* Avoid undefined behavior introduced in 1.4.9b in the `format' builtin
+  when handling %c.  However, this area of code has never been documented,
+  and currently does not match the POSIX behavior of printf(1), so it may
+  have further changes in the next version.
 
 Version 1.4.9b - 29 May 2007, by Eric Blake  (CVS version 1.4.9a)
 
@@ -19,7 +24,9 @@ Version 1.4.9b - 29 May 2007, by Eric Bl
   more predictably when stdin is seekable.
 * The `format' builtin now understands formats such as %a, %A, and %'hhd,
   and works around a number of platform printf bugs.  Furthermore, the
-  sequence format(%*.*d,-1,-1,1) no longer outputs random data.
+  sequence format(%*.*d,-1,-1,1) no longer outputs random data.  However,
+  some non-compliant platforms such as mingw still have known bugs in
+  strtod that may cause testsuite failures.
 * The testsuite is improved to also run gnulib portability tests for the
   features that M4 imports from gnulib.
 
Index: TODO
===================================================================
RCS file: /sources/m4/m4/TODO,v
retrieving revision 1.1.1.1.2.2
diff -u -p -r1.1.1.1.2.2 TODO
--- TODO        22 Aug 2006 16:13:38 -0000      1.1.1.1.2.2
+++ TODO        9 Jul 2007 12:50:54 -0000
@@ -4,6 +4,9 @@ Tell <address@hidden> if you feel like v
 of these ideas, listed more or less in decreasing order of priority.
 
 * Features or problems
+  - Fix format() builtin to handle %c more like printf(1) in the shell
+        http://lists.gnu.org/archive/html/bug-m4/2007-05/msg00047.html
+    Also, gnulib needs help to overcome mingw bugs related to format().
   - Update documentation from accumulated mail about it
   - Study synclines at the very beginning of each diverted sequence
   - Make eval work on bignums - the 32 bits limit is artificial
@@ -34,7 +37,7 @@ mode: outline
 outline-regexp: " *[-+*.] \\|"
 End:
 
-Copyright (C) 2000, 2006 Free Software Foundation, Inc.
+Copyright (C) 2000, 2006, 2007 Free Software Foundation, Inc.
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.2 or
Index: src/format.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/format.c,v
retrieving revision 1.1.1.1.2.7
diff -u -p -r1.1.1.1.2.7 format.c
--- src/format.c        29 May 2007 13:19:47 -0000      1.1.1.1.2.7
+++ src/format.c        9 Jul 2007 12:50:54 -0000
@@ -85,9 +85,9 @@ format (struct obstack *obs, int argc, t
 
   /* Buffer and stuff.  */
   char *str;                   /* malloc'd buffer of formatted text */
-  enum {INT, LONG, DOUBLE, STR} datatype;
+  enum {CHAR, INT, LONG, DOUBLE, STR} datatype;
 
-  f = fmt = (const char *) ARG_STR (argc, argv);
+  f = fmt = ARG_STR (argc, argv);
   memset (ok, 0, sizeof ok);
   for (;;)
     {
@@ -176,13 +176,11 @@ format (struct obstack *obs, int argc, t
          fmt++;
        }
       else
-       {
-         while (isdigit (to_uchar (*fmt)))
-           {
-             width = 10 * width + *fmt - '0';
-             fmt++;
-           }
-       }
+       while (isdigit (to_uchar (*fmt)))
+         {
+           width = 10 * width + *fmt - '0';
+           fmt++;
+         }
 
       /* Maximum precision; an explicit negative precision is the same
         as not giving the precision.  A lone '.' is a precision of 0.  */
@@ -238,14 +236,13 @@ format (struct obstack *obs, int argc, t
            fmt--;
          continue;
        }
-      *p++ = c;
-      *p = '\0';
 
       /* Specifiers.  We don't yet recognize C, S, n, or p.  */
       switch (c)
        {
        case 'c':
-         datatype = INT;
+         datatype = CHAR;
+         p -= 2; /* %.*c is undefined, so undo the '.*'.  */
          break;
 
        case 's':
@@ -275,9 +272,15 @@ format (struct obstack *obs, int argc, t
        default:
          abort ();
        }
+      *p++ = c;
+      *p = '\0';
 
-      switch(datatype)
+      switch (datatype)
        {
+       case CHAR:
+         str = xasprintf (fstart, width, ARG_INT(argc, argv));
+         break;
+
        case INT:
          str = xasprintf (fstart, width, prec, ARG_INT(argc, argv));
          break;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]