Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Mar 2000 19:03:47 +0200 (CEST)
From:      mikko@dynas.se
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   bin/17694: wcstombs() and mbstowcs() unable to handle NULL argument
Message-ID:  <200003301703.TAA00862@mt.dynas.se>

next in thread | raw e-mail | index | archive | help

>Number:         17694
>Category:       bin
>Synopsis:       wcstombs(), mbstowcs() not complying with standard
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Mar 30 09:50:01 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Mikko Työläjärvi
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
>Environment:

   FreeBSD 4.0 and 5.x

>Description:

Looks like these two functions are supposed to be able to take
a NULL destination pointer (the first one), in which case they
should return the length required to do the actual copy.

Stubled across this whilst porting code that made use of this feature
to figure out how much memory to allocate.

C.f.  Solaris man-pages (e.g. at docs.sun.com)
      and "Single UNIX Specification" at
      <http://www.opengroup.org/onlinepubs/007908799/xsh/mbstowcs.html>;

"If s is a null pointer, wcstombs() returns the length required to
 convert the entire array regardless of the value of n, but no
 values are stored. function returns the number of bytes required for
 the character array."  ["s" is the output string]

and

"If pwcs is a null pointer, mbstowcs() returns the length required to
 convert the entire array regardless of the value of n, but no values
 are stored." ["pwcs" is the output string]


>How-To-Repeat:

#include <stdlib.h>
#include <locale.h>

int
main(int argc, char **argv)
{
   int len;

   setlocale(LC_ALL, "C");
   len = mbstowcs(NULL, "SE", 0);
   printf("len = %d (should be 2)\n", len);
}

>Fix:

Suggested patch (actually somewhat tested with different arguments,
but not in real multibyte locales, and relies on all flavours of
sputrune being able to handle NULL args):

--- ansi.c.org	Thu Mar 30 18:45:34 2000
+++ ansi.c	Thu Mar 30 18:44:57 2000
@@ -103,16 +103,22 @@
 	size_t n;
 {
 	char const *e;
+	wchar_t wc;
 	int cnt = 0;
 
-	if (!pwcs || !s)
+	if (!s)
 		return (-1);
 
-	while (n-- > 0) {
-		*pwcs = sgetrune(s, MB_LEN_MAX, &e);
-		if (*pwcs == _INVALID_RUNE)
+	for (;;) {
+		wc = sgetrune(s, MB_LEN_MAX, &e);
+		if (wc == _INVALID_RUNE)
 			return (-1);
-		if (*pwcs++ == 0)
+		if (pwcs) {
+			if (n-- <= 0)
+				break;
+			*pwcs++ = wc;
+		}
+		if (wc == 0)
 			break;
 		s = e;
 		++cnt;
@@ -129,23 +135,27 @@
 	char *e;
 	int cnt, nb;
 
-	if (!pwcs || !s || n > INT_MAX)
+	if (!pwcs || n > INT_MAX)
 		return (-1);
 
-	nb = n;
 	cnt = 0;
-	while (nb > 0) {
+	for (;;) {
 		if (*pwcs == 0) {
-			*s = 0;
+			if (s)
+				*s = 0;
 			break;
 		}
-		if (!sputrune(*pwcs++, s, nb, &e))
+		if (!(nb = sputrune(*pwcs++, s, nb, &e)))
 			return (-1);		/* encoding error */
 		if (!e)			/* too long */
 			return (cnt);
-		cnt += e - s;
-		nb -= e - s;
-		s = e;
+		cnt += nb;
+		n -= nb;
+		if (s) {
+			if (n <= 0)
+				break;
+			s = e;
+		}
 	}
 	return (cnt);
 }


>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200003301703.TAA00862>