This is the mail archive of the newlib@sourceware.org mailing list for the newlib 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] stdio/vfprintf.c: Don't drop out on invalid chars in format string


Hi,

assume the following test application:

  #include <stdio.h>
  #include <string.h>
  #include <locale.h>

  int
  main ()
  {
    char buf[32];
    int ret;

    setlocale (LC_ALL, "en_US.UTF-8");
    memset (buf, 0, sizeof buf);
    ret = sprintf (buf, "\333%s", "ABCD");
    printf ("(%d) %02x %02x %02x %02x %02x\n",
	    ret, buf[0], buf[1], buf[2], buf[3], buf[4]);
    return 0;
  }

It contains a character in the format string "\333", which is invalid
in the current charset (UTF-8).  Running this application on Linux or
Solaris results in the following output:

  (5) ffffffdb 41 42 43 44

Running this under newlib/Cygwin, the result is:

  (0) 0 0 0 0 0

In newlib, the loop looking for '%' in the format string converts the
format string chars into wide chars, and then compares the character
with a '%'.  The problem is that the vfprintf function simply exits as
soon as an invalid char is found in the format string and returns the
number of characters printed so far.  This is not defined in POSIX.
Either printf is supposed to go ahead, or it is allowed to exit with
a return value of -1 and errno set to EILSEQ.

For compatiblity with Linux and Solaris, I'd like to opt for just going
ahaead and copy the invalid byte in the format string unchanged to the
output.  The patch below will do that.

Ok to apply?


Thanks,
Corinna


	* libc/stdio/vfprintf.c (_VFPRINTF_R): Just wave bytes invalid in
	the current charset through.


Index: libc/stdio/vfprintf.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/vfprintf.c,v
retrieving revision 1.76
diff -u -p -r1.76 vfprintf.c
--- libc/stdio/vfprintf.c	18 Nov 2009 09:49:56 -0000	1.76
+++ libc/stdio/vfprintf.c	9 Jan 2010 11:03:39 -0000
@@ -724,8 +724,13 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap)
 	        cp = fmt;
 #ifdef _MB_CAPABLE
 	        while ((n = __mbtowc (data, &wc, fmt, MB_CUR_MAX,
-				      __locale_charset (), &state)) > 0) {
-                    if (wc == '%')
+				      __locale_charset (), &state)) != 0) {
+		    if (n < 0) {
+			/* Wave invalid chars through. */
+			memset (&state, 0, sizeof state);
+			n = 1;
+		    }
+                    else if (wc == '%')
                         break;
                     fmt += n;
 		}


-- 
Corinna Vinschen
Cygwin Project Co-Leader
Red Hat


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