When the target pointer 'pwcs' passed to mbsrtowcs() is NULL, mbsrtowcs()
authorstsp <stsp@openbsd.org>
Tue, 3 Aug 2010 11:23:37 +0000 (11:23 +0000)
committerstsp <stsp@openbsd.org>
Tue, 3 Aug 2010 11:23:37 +0000 (11:23 +0000)
is supposed to ignore the 'n' parameter and return the number of wide
characters needed to represent the given multi-byte character sequence.

However, in the special case where 'pwcs' is NULL and 'n' is zero, our
mbsrtowcs() implementation for single-byte locales mistakenly returned zero.
Before the UTF-8 locale was added, this bug was invisible to callers of
mbstowcs() because mbstowcs() handled this special case itself.
But our new mbstowcs() implementation simply forwards to the locale-specific
mbsrtowcs() implementation and expects it to do the right thing.

The "awesome" window manager's "Run:" command prompt uses mbstowcs() to
measure how many (possibly multi-byte) characters a user has typed, and
due to this bug would always be tricked into thinking the user had entered
zero characters when a single-byte locale was used.

Found after prodding by dcoppa.

ok deraadt sthen espie

lib/libc/citrus/citrus_none.c

index b7b039e..e0dfafd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: citrus_none.c,v 1.1 2010/07/27 16:59:03 stsp Exp $ */
+/*     $OpenBSD: citrus_none.c,v 1.2 2010/08/03 11:23:37 stsp Exp $ */
 /*     $NetBSD: citrus_none.c,v 1.18 2008/06/14 16:01:07 tnozaki Exp $ */
 
 /*-
@@ -83,20 +83,14 @@ _citrus_none_ctype_mbsrtowcs(wchar_t * __restrict pwcs,
        if (!s || !*s)
                return 0;
 
-       if (n != 0) {
-               if (pwcs != NULL) {
-                       do {
-                               if ((*pwcs++ = (wchar_t)(unsigned char)*(*s)++) == 0)
-                                       break;
-                               count++;
-                       } while (--n != 0);
-               } else {
-                       do {
-                               if (((wchar_t)*(*s)++) == 0)
-                                       break;
-                               count++;
-                       } while (--n != 0);
-               }
+       if (pwcs == NULL)
+               return strlen(*s);
+
+       while (n > 0) {
+               if ((*pwcs++ = (wchar_t)(unsigned char)*(*s)++) == 0)
+                       break;
+               count++;
+               n--;
        }
        
        return count;