Subject: lib/18269: wc(r)tomb()'s behavior is out of the standard, ISO-C/SUS.
To: None <gnats-bugs@gnats.netbsd.org>
From: wurlitzer@infoseek.jp <wurlitzer@infoseek.jp>
List: netbsd-bugs
Date: 09/12/2002 05:05:56
>Number:         18269
>Category:       lib
>Synopsis:       wc(r)tomb()'s behavior is out of the standard, ISO-C/SUS.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Sep 11 16:16:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     wurlitzer@infoseek.jp
>Release:        NetBSD 1.6_RC1
>Organization:
--
wurlitzer@infoseek.jp <wurlitzer@infoseek.jp>
>Environment:
System: NetBSD fly 1.6_RC1 NetBSD 1.6_RC1 (FLY) #0: Mon Aug 26 11:56:35 JST 2002 root@fly:/usr/src/sys/arch/i386/compile/FLY i386
Architecture: i386
Machine: i386
libc version: libc.so.12.83 lib{BIG5,EUC,EUCTW,ISO2022,MSKanji,UTF8}.so.4.0
>Description:

1) wcrtomb() problems

ISO-C/SUS says,
size_t wcrtomb(const char *s, wchar_t wc, mbstate_t *state);

if 's' is a null pointer, the wcrtomb() function is equivalent to the call
wcrtomb(buf, L'\0', ps), where buf is an internal buffer.

but NetBSD libc doesn't check whether 's' is a null pointer or not.
as a result, Segmentation fault caused when feeding 's' as NULL,

2) wctomb() problems.

ISO-C/SUS says,
int wctomb(char *s, wchar_t wc);

A call with s as a null pointer causes this function to return a
non-zero value if encodings have state dependency, and 0 otherwise.

but NetBSD libc force to convert 'wc' by using an internal buffer,
and return (size_t) 1.

>How-To-Repeat:

compile and run following simple test code.

-- test.c start --
#include <locale.h>
#include <wchar.h>
int main(void) {
  size_t len1;
  int len2;
  mbstate_t s;

  setlocale (LC_CTYPE, "ja_JP.eucJP");

  memset(&s, 0, sizeof(s));
  /* len1 expected to be 1 (glibc does),
      but NetBSD may throws Segmentation fault */
  len1 = wcrtomb(NULL, 0, &s);
  printf("%d\n", len1);

  /* len2 expected to be 0 (glibc does),
      but NetBSD may returns 1 */
  len2 = wctomb(NULL, 0);
  printf("%d\n", len2);

  return 0;
}
-- test.c end --

>Fix:

1) wcrtomb
Index: citrus_euc.c
===================================================================
RCS file: /home/cvs/NetBSD/basesrc/lib/libc/citrus/modules/citrus_euc.c,v
retrieving revision 1.5
diff -u -r1.5 citrus_euc.c
--- citrus_euc.c    2002/03/28 10:53:48    1.5
+++ citrus_euc.c    2002/09/10 07:43:54
@@ -300,10 +300,16 @@
 {
     wchar_t m, nm;
     int cs, i;
+    char buf[MB_LEN_MAX];
 
+    if (s == NULL) {
+        _citrus_EUC_init_state(ei, psenc);
+        s = buf;
+        wchar = (wchar_t)0;
+    }
+
     _DIAGASSERT(ei != NULL);
     _DIAGASSERT(nresult != 0);
-    _DIAGASSERT(s != NULL);
 
     m = wc & ei->mask;
     nm = wc & ~m;

2) wctomb
Index: citrus_ctype_template.h
===================================================================
RCS file: /home/cvs/NetBSD/basesrc/lib/libc/citrus/citrus_ctype_template.h,v
retrieving revision 1.13.2.1
diff -u -r1.13.2.1 citrus_ctype_template.h
--- citrus_ctype_template.h    2002/05/24 21:55:23    1.13.2.1
+++ citrus_ctype_template.h    2002/09/11 17:29:52
@@ -606,12 +606,15 @@
 {
     size_t nr;
     int err = 0;
-    char s0[MB_LEN_MAX];
 
     _DIAGASSERT(cl != NULL);
 
-    if (s==NULL)
-        s = s0;
+    if (s==NULL) {
+      _FUNCNAME(init_state)(_CEI_TO_EI(_TO_CEI(cl)),
+                        &_CEI_TO_STATE(_TO_CEI(cl), wctomb));
+          *nresult = _ENCODING_IS_STATE_DEPENDENT :
+          return 0;
+        }
 
     err = _FUNCNAME(wcrtomb_priv)(cl, s,
               _ENCODING_MB_CUR_MAX(_CEI_TO_EI(_TO_CEI(cl))),
>Release-Note:
>Audit-Trail:
>Unformatted: