From xm@brain.cc.rsu.ru  Mon Nov 10 23:49:27 2003
Return-Path: <xm@brain.cc.rsu.ru>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 0FE2B16A4D1
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 10 Nov 2003 23:49:26 -0800 (PST)
Received: from brain.cc.rsu.ru (brain.cc.rsu.ru [195.208.252.154])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 5EF5343F93
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 10 Nov 2003 23:49:24 -0800 (PST)
	(envelope-from xm@brain.cc.rsu.ru)
Received: from brain.cc.rsu.ru (localhost [127.0.0.1])
	by brain.cc.rsu.ru (8.12.10/8.12.9) with ESMTP id hAB7nI6E097038
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 11 Nov 2003 10:49:18 +0300 (MSK)
	(envelope-from xm@brain.cc.rsu.ru)
Received: (from xm@localhost)
	by brain.cc.rsu.ru (8.12.10/8.12.9/Submit) id hAB7nIxw097037;
	Tue, 11 Nov 2003 10:49:18 +0300 (MSK)
	(envelope-from xm)
Message-Id: <200311110749.hAB7nIxw097037@brain.cc.rsu.ru>
Date: Tue, 11 Nov 2003 10:49:18 +0300 (MSK)
From: Aristarkh A Zagorodnikov <xm-freebsd@x-infinity.com>
Reply-To: Aristarkh A Zagorodnikov <xm-freebsd@x-infinity.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: Wide-character string formatting functions overrun internal buffer 
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         59167
>Category:       bin
>Synopsis:       Wide-character string formatting functions overrun internal buffer
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    tjr
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Nov 10 23:50:23 PST 2003
>Closed-Date:    Wed Nov 12 00:50:04 PST 2003
>Last-Modified:  Wed Nov 12 00:50:04 PST 2003
>Originator:     Aristarkh A Zagorodnikov
>Release:        FreeBSD 5.1-CURRENT i386
>Organization:
X-Infinity Software
>Environment:
System: FreeBSD brain.cc.rsu.ru 5.1-CURRENT FreeBSD 5.1-CURRENT #0: Mon Sep 22 16:20:31 MSD 2003 os@brain.cc.rsu.ru:/usr/obj/usr/src/sys/brain.athlon-xp.HEAD.2003-09-23 i386


	
>Description:
	The problem manifests itself in wide-character string formatting functions (namely swprintf/vswprintf).
Consider the target buffer of arbitrary size (for simplicity let it be large enough to contain entire output). When swprintf or
vswprintf prints to this buffer, it fails inside the __vfwprintf function or shortly afterwards if output exceeds 128 characters.
This is due to overflow of internal FILE buffer which seems to never get reallocated in wide-character string formatting
functions.

P.S. this problem seems to exist on other BSD-based systems - I first occured it in Darwin 7.0 (MacOS X 10.3)

	
>How-To-Repeat:
The following is a near-minimal example of swprintf failure.

$ cat swprintf-fail.c
#include <stdio.h>
#include <wchar.h>

int main(int argc, char* argv)
{
        wchar_t buffer[200];
        swprintf(buffer, 199,
                L"01234568901234568901234568901234568901234568901234568901234568901234568901234568901234568901234568901234568901234568901234568901");
        return 0;
}

$ gcc swprintf-fail.c -g3 -O0
$ ./a.out
Bus error (core dumped)

	
>Fix:
Note that the following conclusions are made after only a brief looking at the problem code so they may be partially or event completely wrong.

The fix involves support for __SSTR and __SALC FILE flags in output function which is called from internal formatting function
__vfwprintf. Currently, __vfwprintf uses __fputwc for output, which in turn uses __sputc which blindly writes characters and
calls __swbuf when buffer is exhausted. In contrast, single-character internal formatting function __vfprintf uses __sfvwrite function
to write output, which correctly handles __SSTR and __SALC FILE flags (reallocating the buffer) and does not exhibit the problem.

So, proposed solutions are:
1. rewrite __vfwprintf output to use something other than __fputwc (i.e. use __sfvwrite with some wcs->mbcs preprocessing?)
2. fix __fputwc to support the __SSTR and __SALC flags (bad idea, this function should be fast)
3. fix __swbuf to support the __SSTR and __SALC flags (looks good to me, especially because it's called at the exact time when buffer is about to overflow)

I already concluded a quick patch using (3), but not tested it good enough, so I'm not posting it here.
If someone considers that my patch can be of any value, I will gladly submit it for review.

	


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->tjr 
Responsible-Changed-By: das 
Responsible-Changed-When: Tue Nov 11 12:40:00 PST 2003 
Responsible-Changed-Why:  
Assign to Mr. wide character 

http://www.freebsd.org/cgi/query-pr.cgi?pr=59167 

From: Tim Robbins <tjr@freebsd.org>
To: bug-followup@freebsd.org
Cc:  
Subject: Re: bin/59167
Date: Wed, 12 Nov 2003 08:40:03 +1100

 Try this patch. It makes __vfwprintf() use __sfvwrite() instead of __fputwc()
 when the destination is a fake string file. This is probably the simplest
 way to fix the bug.
 
 (I just noticed that the __inline is probably useless here, so if I commit
 this, I'll remove it.)
 
 --- vfwprintf.c.old	Wed Nov 12 08:30:10 2003
 +++ vfwprintf.c	Wed Nov 12 08:29:41 2003
 @@ -114,6 +114,8 @@
  };
  
  static int	__sbprintf(FILE *, const wchar_t *, va_list);
 +static __inline wint_t
 +		__xfputwc(wchar_t, FILE *);
  static wchar_t	*__ujtoa(uintmax_t, wchar_t *, int, int, const wchar_t *, int,
  		    char, const char *);
  static wchar_t	*__ultoa(u_long, wchar_t *, int, int, const wchar_t *, int,
 @@ -156,6 +158,34 @@
  }
  
  /*
 + * Like __fputwc, but handles fake string (__SSTR) files properly.
 + * File must already be locked.
 + */
 +static __inline wint_t
 +__xfputwc(wchar_t wc, FILE *fp)
 +{
 +	char buf[MB_LEN_MAX];
 +	struct __suio uio;
 +	struct __siov iov;
 +	size_t i, len;
 +	int ret;
 +
 +	if ((fp->_flags & __SSTR) == 0)
 +		return (__fputwc(wc, fp));
 +
 +	if ((len = wcrtomb(buf, wc, NULL)) == (size_t)-1) {
 +		fp->_flags |= __SERR;
 +		return (WEOF);
 +	}
 +	uio.uio_iov = &iov;
 +	uio.uio_resid = len;
 +	uio.uio_iovcnt = 1;
 +	iov.iov_base = buf;
 +	iov.iov_len = len;
 +	return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF);
 +}
 +
 +/*
   * Macros for converting digits to letters and vice versa
   */
  #define	to_digit(c)	((c) - '0')
 @@ -529,7 +559,7 @@
  	 */
  #define	PRINT(ptr, len)	do {			\
  	for (n3 = 0; n3 < (len); n3++)		\
 -		__fputwc((ptr)[n3], fp);	\
 +		__xfputwc((ptr)[n3], fp);	\
  } while (0)
  #define	PAD(howmany, with)	do {		\
  	if ((n = (howmany)) > 0) {		\
State-Changed-From-To: open->closed 
State-Changed-By: tjr 
State-Changed-When: Wed Nov 12 00:49:35 PST 2003 
State-Changed-Why:  
Fixed in -current, thanks for the report. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=59167 
>Unformatted:
