From nobody@FreeBSD.org  Tue Jan 31 23:06:53 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id D7CA4106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 31 Jan 2012 23:06:53 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id BC0DC8FC15
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 31 Jan 2012 23:06:53 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id q0VN6rZV091431
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 31 Jan 2012 23:06:53 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id q0VN6roO091429;
	Tue, 31 Jan 2012 23:06:53 GMT
	(envelope-from nobody)
Message-Id: <201201312306.q0VN6roO091429@red.freebsd.org>
Date: Tue, 31 Jan 2012 23:06:53 GMT
From: Matthew Story <matthewstory@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: vsprintf/vswprintf return error (EOF) on success if __SERR flag is already set on file
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         164674
>Category:       kern
>Synopsis:       [patch] [libc] vfprintf/vfwprintf return error (EOF) on success if __SERR flag is already set on file
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-standards
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jan 31 23:10:09 UTC 2012
>Closed-Date:    
>Last-Modified:  Mon Apr  2 20:10:02 UTC 2012
>Originator:     Matthew Story
>Release:        9.0-Release
>Organization:
>Environment:
FreeBSD matt9fromouterspace 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan  3 07:15:25 UTC 2012     root@obrian.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
The printf family of functions behaves unpredictably if the file passed to the function has the __SERR flag set in _flags.  The one consistency across all of the cases detailed below is that regardless of the number of bytes written to the file, and the success/failure of that operation, the printf functions (printf, fprintf, wprintf, fwprintf) will always return -1 (EOF).

 * For the case of an unbuffered file,  the operation currently fails transmitting no bytes, and returns -1.
 * For the case of a buffered file, the operation transmits all bytes and the function returns -1.  

The problem is that the behavior here is inconsistent, and should not be.   The question is wether all should be made to fail consistently and transmit no bytes if __SERR is set on _flags, or if failure should be determined based on the success of byte transmission, discounting file state.

Per the ISO/IEC 9899:201x (C11) Section 7.21.6.1, 14:

The fprintf function returns the number of characters transmitted, or a negative value if an output or encoding error occurred.

My reading of this specification is that success should be determined based on byte-transmission, and should not factor-in file state.  In addition to the ISO standard, the glibc implementation will reliably succeed with any error flag set if bytes are successfully transmitted (although it will transmit partial messages prior to successful conversion, which is unfortunate).

The attached patch makes the operation on buffered and unbuffered files consistent across the affected printf/wprintf functions, determines success/failure based on successful byte-transmission alone, and preserves _flags state for __SERR as passed in.

I originally discovered this behavior through black-box testing ``%<n>'' behavior against data-types through programmatic exhaustion, although a more likely cause of file error state is reading from a file open in write mode, prior to writing to that file (which is the example used in the repeat steps below).
>How-To-Repeat:
/* this simple program demonstrates behavior on buffered (stdout) and unbuffered (stderr) files */
#include <stdio.h>
#define HELLO   "Hello, world\n"

int
main() {
        /* make sure everything is nice and clean */
        clearerr(stdout);
        /* read from write-only file, should cause an error */
        fgetc(stdout);
        printf("stdout is buffered, and %s an error\n",
                ferror(stdout) ? "has":"doesn't have");

        printf("bytes transmitted without replace: %d\n",
                printf(HELLO));
        printf("bytes transmitted with replace: %d\n",
                printf("%s", HELLO));

        clearerr(stderr);
        /* read from write-only file, should cause an error */
        fgetc(stderr);
        /*
         * print diagnostics to stdout, because some will not
         * print to stderr correctly if stderr has an error
         */
        printf("stderr is unbuffered, and %s an error\n",
                ferror(stderr) ? "has":"doesn't have");
        printf("bytes transmitted without replace: %d\n",
                fprintf(stderr, HELLO));
        printf("bytes transmitted with replace: %d\n",
                fprintf(stderr, "%s", HELLO));

        return 0;
}
>Fix:
See patch, my fix is to store and then unset the error flag inside of the exclusive lock, and then to reset the error flag to the original (or new) state after the vs(w)printf prior to releasing the exclusive lock.

this change maintains the ferror state of the file as passed in or as set by __vfprintf, but allows for vs(w)printf to determine success of the print operation independent of the state of the file as passed in.  there may be other ways to handle this more gracefully, but this change seems to me to be the safest and most minimally impacting solution.

The patch applies cleanly on both 8.2/9.0, and includes an additional regression test for stdio pertaining to correctness of return codes.

Patch attached with submission follows:

diff -urN old/lib/libc/stdio/vfprintf.c new/lib/libc/stdio/vfprintf.c
--- old/lib/libc/stdio/vfprintf.c	2012-01-31 17:35:31.025336246 -0500
+++ new/lib/libc/stdio/vfprintf.c	2012-01-31 17:44:50.078652303 -0500
@@ -265,14 +265,24 @@
 
 {
 	int ret;
+	short orig_err;
 
 	FLOCKFILE(fp);
+	/*
+	 * store flags, unset errors, success of printf is
+	 * independent of previous errors on the fd
+	 */
+	orig_err = fp->_flags & __SERR;
+	fp->_flags &= ~__SERR;
+
 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
 	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
 	    fp->_file >= 0)
 		ret = __sbprintf(fp, fmt0, ap);
 	else
 		ret = __vfprintf(fp, fmt0, ap);
+
+	fp->_flags |= orig_err & __SERR;
 	FUNLOCKFILE(fp);
 	return (ret);
 }
diff -urN old/lib/libc/stdio/vfwprintf.c new/lib/libc/stdio/vfwprintf.c
--- old/lib/libc/stdio/vfwprintf.c	2012-01-31 17:35:31.021336063 -0500
+++ new/lib/libc/stdio/vfwprintf.c	2012-01-31 17:46:28.106128024 -0500
@@ -347,14 +347,24 @@
 
 {
 	int ret;
+	short orig_err;
 
 	FLOCKFILE(fp);
+	/*
+	 * store flags, unset errors, success of wprintf is
+	 * independent of previous errors on the fd
+	 */
+	orig_err = fp->_flags & __SERR;
+	fp->_flags &= ~__SERR;
+
 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
 	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
 	    fp->_file >= 0)
 		ret = __sbprintf(fp, fmt0, ap);
 	else
 		ret = __vfwprintf(fp, fmt0, ap);
+
+	fp->_flags |= orig_err & __SERR;
 	FUNLOCKFILE(fp);
 	return (ret);
 }
diff -urN old/tools/regression/lib/libc/stdio/Makefile new/tools/regression/lib/libc/stdio/Makefile
--- old/tools/regression/lib/libc/stdio/Makefile	2012-01-31 17:36:04.247820192 -0500
+++ new/tools/regression/lib/libc/stdio/Makefile	2012-01-31 17:41:30.201758177 -0500
@@ -1,6 +1,6 @@
 # $FreeBSD: stable/9/tools/regression/lib/libc/stdio/Makefile 189142 2009-02-28 06:39:39Z das $
 
-TESTS=	test-getdelim test-perror test-print-positional test-printbasic test-printfloat test-scanfloat
+TESTS=	test-getdelim test-perror test-print-positional test-printbasic test-printfloat test-scanfloat test-printreturn
 CFLAGS+= -lm
 
 .PHONY: tests
diff -urN old/tools/regression/lib/libc/stdio/test-printreturn.c new/tools/regression/lib/libc/stdio/test-printreturn.c
--- old/tools/regression/lib/libc/stdio/test-printreturn.c	1969-12-31 19:00:00.000000000 -0500
+++ new/tools/regression/lib/libc/stdio/test-printreturn.c	2012-01-31 17:41:30.200756664 -0500
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2012 Matthew Story <matthewstory@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	notice, this list of conditions and the following disclaimer in the
+ *	documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Tests for correct return codes from f(w)printf
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <wchar.h>
+#include <errno.h>
+#include <string.h>
+
+#define BATTERY_OK "ok %d - printreturn\n"
+
+#define run_battery(void)  \
+	_run_battery(__LINE__)
+
+void smash_stack(void);
+void _run_battery(int line);
+int battery = 1;
+
+int
+main() {
+	/*
+	 * All tests occur on stdout, this makes the tests quite noisy.
+	 * but keeps them contained -- e.g. no reliance on external 
+	 * files, or on manipulating file struct internals.
+	 */
+
+	printf("1..12\n");
+	/* 
+	 * without errors
+	 */
+	clearerr(stdout);
+
+	/* line-buffered */
+	setvbuf(stdout, (char *)NULL, _IOLBF, 0);
+	run_battery();
+
+	/* unbuffered */
+	setvbuf(stdout, (char *)NULL, _IONBF, 0);
+	run_battery();
+
+	/* fully-buffered */
+	setvbuf(stdout, (char *)NULL, _IOFBF, 0);
+	run_battery();
+
+	/*
+	 * success with errors, would rather not manipulate _flags * directly, but
+	 * can't find another direct way to set error, without an actual error.
+	 */
+	stdout->_flags |= __SERR;
+
+	/* line-buffered */
+	setvbuf(stdout, (char *)NULL, _IOLBF, 0);
+	run_battery();
+
+	/* unbuffered */
+	setvbuf(stdout, (char *)NULL, _IONBF, 0);
+	run_battery();
+
+	/* fully-buffered */
+	setvbuf(stdout, (char *)NULL, _IOFBF, 0);
+	run_battery();
+
+	return 0;
+}
+
+/* taken from test-printbasic.c */
+void
+smash_stack(void)
+{
+	static uint32_t junk = 0xdeadbeef;
+	uint32_t buf[512];
+	int i;
+
+	for (i = 0; i < sizeof(buf) / sizeof(buf[0]); i++)
+		buf[i] = junk;
+}
+
+void
+_run_battery(int line) {
+#define BUF 100
+	extern int battery;
+	wchar_t ws[BUF], wfmt[BUF];	
+	char s[BUF];
+
+	/* regular width tests, no replacement, and replacement */
+	smash_stack();
+	sprintf(s, BATTERY_OK, battery);
+	if (0 > fprintf(stdout, s)) {
+		fprintf(stderr, 
+			"%d: failure in no replace printf (%d)\n",
+			line, errno);
+		abort();
+	}
+	++battery;
+	smash_stack();
+	if (0 > fprintf(stdout, BATTERY_OK, battery)) {
+		fprintf(stderr, "%d: failure in replace printf (%d)\n", line, errno);
+		abort();
+	}
+	++battery;
+
+	/* wide tests, no replacement, and replacement */
+	smash_stack();
+	mbstowcs(wfmt, BATTERY_OK, BUF - 1);
+	swprintf(ws, sizeof(ws) / sizeof(ws[0]), wfmt, battery);
+	if (0 > fwprintf(stdout, ws)) {
+		fprintf(stderr,
+			"%d: failure in no replace wprintf (%d)\n",
+			line, errno);
+		abort();
+	}
+	++battery;
+	smash_stack();
+	if (0 > fwprintf(stdout, wfmt, battery)) {
+		fprintf(stderr, "%d: failure in replace wprintf (%d)\n", line, errno);
+		abort();
+	}
+	++battery;
+}


>Release-Note:
>Audit-Trail:

From: Matthew Story <matthewstory@gmail.com>
To: freebsd-gnats-submit@freebsd.org, freebsd-bugs@freebsd.org
Cc:  
Subject: Re: kern/164674: vsprintf/vswprintf return error (EOF) on success if
 __SERR flag is already set on file
Date: Tue, 31 Jan 2012 18:16:22 -0500

 --20cf3071cee2bd737d04b7db2626
 Content-Type: text/plain; charset=ISO-8859-1
 
 On Tue, Jan 31, 2012 at 6:06 PM, Matthew Story <matthewstory@gmail.com>wrote:
 
 > >Synopsis:       vsprintf/vswprintf return error (EOF) on success if
 > __SERR flag is already set on file
 >
 
 this synopsis should read "vfprintf/vfwprintf return ...", apologies for
 the typo, can someone with appropriate edit privileges change this?
 
 thanks
 
 --20cf3071cee2bd737d04b7db2626
 Content-Type: text/html; charset=ISO-8859-1
 Content-Transfer-Encoding: quoted-printable
 
 On Tue, Jan 31, 2012 at 6:06 PM, Matthew Story <span dir=3D"ltr">&lt;<a hre=
 f=3D"mailto:matthewstory@gmail.com">matthewstory@gmail.com</a>&gt;</span> w=
 rote:<br><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=
 =3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
 &gt;Synopsis: =A0 =A0 =A0 vsprintf/vswprintf return error (EOF) on success =
 if __SERR flag is already set on file<br></blockquote><div><br></div><div>t=
 his synopsis should read &quot;vfprintf/vfwprintf return ...&quot;, apologi=
 es for the typo, can someone with appropriate edit privileges change this? =
 =A0</div>
 <div><br></div><div>thanks</div></div>
 
 --20cf3071cee2bd737d04b7db2626--

From: Mark Linimon <linimon@lonesome.com>
To: Matthew Story <matthewstory@gmail.com>
Cc: freebsd-gnats-submit@freebsd.org
Subject: Re: kern/164674: vsprintf/vswprintf return error (EOF) on success
 if __SERR flag is already set on file
Date: Tue, 31 Jan 2012 18:47:13 -0600

 On Tue, Jan 31, 2012 at 06:16:22PM -0500, Matthew Story wrote:
 > this synopsis should read "vfprintf/vfwprintf return ...", apologies for
 > the typo, can someone with appropriate edit privileges change this?
 
 done.
 
 mcl

From: Matthew Story <matthewstory@gmail.com>
To: Mark Linimon <linimon@lonesome.com>
Cc: freebsd-gnats-submit@freebsd.org
Subject: Re: kern/164674: vsprintf/vswprintf return error (EOF) on success if
 __SERR flag is already set on file
Date: Tue, 31 Jan 2012 20:52:20 -0500

 --f46d0438936d80ad7204b7dd5444
 Content-Type: text/plain; charset=ISO-8859-1
 
 thanks!
 
 On Tue, Jan 31, 2012 at 7:47 PM, Mark Linimon <linimon@lonesome.com> wrote:
 
 > On Tue, Jan 31, 2012 at 06:16:22PM -0500, Matthew Story wrote:
 > > this synopsis should read "vfprintf/vfwprintf return ...", apologies for
 > > the typo, can someone with appropriate edit privileges change this?
 >
 > done.
 >
 > mcl
 >
 
 
 
 -- 
 regards,
 matt
 
 --f46d0438936d80ad7204b7dd5444
 Content-Type: text/html; charset=ISO-8859-1
 Content-Transfer-Encoding: quoted-printable
 
 thanks!<br><br><div class=3D"gmail_quote">On Tue, Jan 31, 2012 at 7:47 PM, =
 Mark Linimon <span dir=3D"ltr">&lt;<a href=3D"mailto:linimon@lonesome.com">=
 linimon@lonesome.com</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_qu=
 ote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex=
 ">
 <div class=3D"im">On Tue, Jan 31, 2012 at 06:16:22PM -0500, Matthew Story w=
 rote:<br>
 &gt; this synopsis should read &quot;vfprintf/vfwprintf return ...&quot;, a=
 pologies for<br>
 &gt; the typo, can someone with appropriate edit privileges change this?<br=
 >
 <br>
 </div>done.<br>
 <br>
 mcl<br>
 </blockquote></div><br><br clear=3D"all"><div><br></div>-- <br>regards,<br>=
 matt<br>
 
 --f46d0438936d80ad7204b7dd5444--

From: Matthew Story <matthewstory@gmail.com>
To: freebsd-gnats-submit@freebsd.org, freebsd-standards@freebsd.org
Cc:  
Subject: Re: kern/164674: vsprintf/vswprintf return error (EOF) on success if
 __SERR flag is already set on file
Date: Thu, 16 Feb 2012 10:55:11 -0500

 --14dae93403056d11e204b916da9f
 Content-Type: text/plain; charset=ISO-8859-1
 
 On Tue, Jan 31, 2012 at 6:06 PM, Matthew Story <matthewstory@gmail.com>wrote:
 
 >
 > >Number:         164674
 > >Category:       kern
 > >Synopsis:       vfprintf/vfwprintf return error (EOF) on success if
 > __SERR flag is already set on file
 >
 
 Apologies for cross-posting, but I think that standards might be a more
 appropriate responsible party for this than -bugs or kern.  See description
 for more info, but the basic issue is that C99 and C11 stipulate that
 fprintf should return -1 "if an output or encoding error occurred."
 Currently, printf is encoding and outputting successfully (on line or fully
 buffered FILEs), but returning -1 if the FILE has an error.  The C99/C11
 specifications make no mention of FILE state in fprintf return conditions,
 so this functionality seems to not conform to the specification, attached
 patch resolves that issue.
 
 
 > >Confidential:   no
 > >Severity:       non-critical
 > >Priority:       low
 > >Responsible:    freebsd-bugs
 > >State:          open
 > [...snip]
 > >Description:
 > The printf family of functions behaves unpredictably if the file passed to
 > the function has the __SERR flag set in _flags.  The one consistency across
 > all of the cases detailed below is that regardless of the number of bytes
 > written to the file, and the success/failure of that operation, the printf
 > functions (printf, fprintf, wprintf, fwprintf) will always return -1 (EOF).
 >
 >  * For the case of an unbuffered file,  the operation currently fails
 > transmitting no bytes, and returns -1.
 >  * For the case of a buffered file, the operation transmits all bytes and
 > the function returns -1.
 >
 > The problem is that the behavior here is inconsistent, and should not be.
 >   The question is wether all should be made to fail consistently and
 > transmit no bytes if __SERR is set on _flags, or if failure should be
 > determined based on the success of byte transmission, discounting file
 > state.
 >
 > Per the ISO/IEC 9899:201x (C11) Section 7.21.6.1, 14:
 >
 > The fprintf function returns the number of characters transmitted, or a
 > negative value if an output or encoding error occurred.
 >
 > My reading of this specification is that success should be determined
 > based on byte-transmission, and should not factor-in file state.  In
 > addition to the ISO standard, the glibc implementation will reliably
 > succeed with any error flag set if bytes are successfully transmitted
 > (although it will transmit partial messages prior to successful conversion,
 > which is unfortunate).
 >
 > The attached patch makes the operation on buffered and unbuffered files
 > consistent across the affected printf/wprintf functions, determines
 > success/failure based on successful byte-transmission alone, and preserves
 > _flags state for __SERR as passed in.
 >
 > [...snip]
 
 
 -- 
 regards,
 matt
 
 --14dae93403056d11e204b916da9f
 Content-Type: text/html; charset=ISO-8859-1
 Content-Transfer-Encoding: quoted-printable
 
 On Tue, Jan 31, 2012 at 6:06 PM, Matthew Story <span dir=3D"ltr">&lt;<a hre=
 f=3D"mailto:matthewstory@gmail.com" target=3D"_blank">matthewstory@gmail.co=
 m</a>&gt;</span> wrote:<br><div class=3D"gmail_quote"><blockquote class=3D"=
 gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-=
 left:1ex">
 
 <br>
 &gt;Number: =A0 =A0 =A0 =A0 164674<br>
 &gt;Category: =A0 =A0 =A0 kern<br>
 &gt;Synopsis: =A0 =A0 =A0 vfprintf/vfwprintf return error (EOF) on success =
 if __SERR flag is already set on file<br></blockquote><div><br></div><div>A=
 pologies for cross-posting, but I think that standards might be a more appr=
 opriate responsible party for this than -bugs or kern. =A0See description f=
 or more info, but the basic issue is that C99 and C11 stipulate that fprint=
 f should return -1 &quot;if an output or encoding error occurred.&quot; Cur=
 rently, printf is encoding and outputting successfully (on line or fully bu=
 ffered FILEs), but returning -1 if the FILE has an error. =A0The C99/C11 sp=
 ecifications make no mention of FILE state in fprintf return conditions, so=
  this functionality seems to not conform to the specification, attached pat=
 ch resolves that issue.</div>
 <div>=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;=
 border-left:1px #ccc solid;padding-left:1ex">
 &gt;Confidential: =A0 no<br>
 &gt;Severity: =A0 =A0 =A0 non-critical<br>
 &gt;Priority: =A0 =A0 =A0 low<br>
 &gt;Responsible: =A0 =A0freebsd-bugs<br>
 &gt;State: =A0 =A0 =A0 =A0 =A0open<br>[...snip]<br>
 &gt;Description:<br>
 The printf family of functions behaves unpredictably if the file passed to =
 the function has the __SERR flag set in _flags. =A0The one consistency acro=
 ss all of the cases detailed below is that regardless of the number of byte=
 s written to the file, and the success/failure of that operation, the print=
 f functions (printf, fprintf, wprintf, fwprintf) will always return -1 (EOF=
 ).<br>
 
 
 <br>
 =A0* For the case of an unbuffered file, =A0the operation currently fails t=
 ransmitting no bytes, and returns -1.<br>
 =A0* For the case of a buffered file, the operation transmits all bytes and=
  the function returns -1.<br>
 <br>
 The problem is that the behavior here is inconsistent, and should not be. =
 =A0 The question is wether all should be made to fail consistently and tran=
 smit no bytes if __SERR is set on _flags, or if failure should be determine=
 d based on the success of byte transmission, discounting file state.<br>
 
 
 <br>
 Per the ISO/IEC 9899:201x (C11) Section 7.21.6.1, 14:<br>
 <br>
 The fprintf function returns the number of characters transmitted, or a neg=
 ative value if an output or encoding error occurred.<br>
 <br>
 My reading of this specification is that success should be determined based=
  on byte-transmission, and should not factor-in file state. =A0In addition =
 to the ISO standard, the glibc implementation will reliably succeed with an=
 y error flag set if bytes are successfully transmitted (although it will tr=
 ansmit partial messages prior to successful conversion, which is unfortunat=
 e).<br>
 
 
 <br>
 The attached patch makes the operation on buffered and unbuffered files con=
 sistent across the affected printf/wprintf functions, determines success/fa=
 ilure based on successful byte-transmission alone, and preserves _flags sta=
 te for __SERR as passed in.<br>
 
 
 <br>[...snip]</blockquote></div><div><br></div>-- <br>regards,<br>matt<br>
 
 --14dae93403056d11e204b916da9f--
Responsible-Changed-From-To: freebsd-bugs->freebsd-standards 
Responsible-Changed-By: eadler 
Responsible-Changed-When: Mon Mar 5 05:25:27 UTC 2012 
Responsible-Changed-Why:  
over to responsible  

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

From: Matthew Story <matthewstory@gmail.com>
To: freebsd-gnats-submit@freebsd.org, freebsd-standards@freebsd.org
Cc:  
Subject: Re: kern/164674: vsprintf/vswprintf return error (EOF) on success if
 __SERR flag is already set on file
Date: Mon, 2 Apr 2012 16:05:24 -0400

 --20cf307813d4f19f8d04bcb7b558
 Content-Type: multipart/alternative; boundary=20cf307813d4f19f8804bcb7b556
 
 --20cf307813d4f19f8804bcb7b556
 Content-Type: text/plain; charset=ISO-8859-1
 
 [excerpts from other thread]
 On Wed, Mar 21, 2012 at 5:45 PM, David Schultz <das@freebsd.org> wrote:
 > On Mon, Mar 12, 2012, Matthew Story wrote:
 >> On Sun, Mar 4, 2012 at 2:03 PM, John Baldwin <jhb@freebsd.org> wrote:
 >>
 >> > My standard-parsing fu is weak.  Can some other folks on this list
 look at
 >> > this PR, figure out what the correct semantics for *fprintf() in this
 case,
 >> > and evaluate the patch?  Thanks.
 > [...]
 >> libc vfprintf currently behaves differently on un|buffered FILEs with
 >> ferror set:
 >>
 >> 1. Unbuffered FILEs
 >>
 >>       -> does not transmit any bytes, and returns -1
 >>
 >> 2. Buffered FILEs (fully buffered, or line buffered)
 >>
 >>       -> transmits all bytes, and returns -1
 >>
 >> I believe that this should be reconciled such that vfprintf (and all
 >> derivatives) returns sucess|failure based on transmission, not taking
 >> ferror state into account, but an alternate solution would be to
 reconcile
 >> the behavior of buffered FILEs with the current behavior of unbuffered
 >> FILEs (e.g. detect ferror state, transmit no bytes and return -1).
 >
 > I agree with this assessment.  When the error indicator is set on
 > a stream, it means that an error has occurred at some point---not
 > that all subsequent operations on the stream should fail.
 >
 > There ought to be a less ugly fix than the one proposed.  Probably
 > the PRINT macro and the various other evil macros in vfprintf()
 > should set ret to EOF, and the following lines in vfprintf.c should
 > be removed:
 >
 >        if (__sferror(fp))
 >                ret = EOF;
 >
 > If vfprintf() is fixed so that printing to a buffered stream
 > always returns success after a successful write (regardless of the
 > prior state of the stream's error indicator), that should fix the
 > problem for unbuffered streams automatically.  Unbuffered streams
 > go through __sbprintf(), which throws away the output if
 > vfprintf() returns -1.
 
 I've followed up on David's suggestion to remove this test and set ret =
 EOF prior to goto error in all relevant places.  I audited all cases where
 __SERR could potentially be set, and determined that all cases are
 correctly setting __SERR, returning error in the bounding function, and
 properly going to error within __vf(w)printf already (I have an exhaustive
 list of these if anyone is curious ...).
 
 Original test program in the PR works with this patch, and the regressions
 for stdio all function as expected.  I took the liberty of cleaning up a
 few return -1's, in favor of return EOF's.
 
 All in all, this is much less ugly than the previous solution.  patch is
 against head ...
 
 -- 
 regards,
 matt
 
 --20cf307813d4f19f8804bcb7b556
 Content-Type: text/html; charset=ISO-8859-1
 Content-Transfer-Encoding: quoted-printable
 
 [excerpts from other thread]<div><div>On Wed, Mar 21, 2012 at 5:45 PM, Davi=
 d Schultz &lt;<a href=3D"mailto:das@freebsd.org">das@freebsd.org</a>&gt; wr=
 ote:</div><div>&gt; On Mon, Mar 12, 2012, Matthew Story wrote:</div><div>&g=
 t;&gt; On Sun, Mar 4, 2012 at 2:03 PM, John Baldwin &lt;<a href=3D"mailto:j=
 hb@freebsd.org">jhb@freebsd.org</a>&gt; wrote:</div>
 <div>&gt;&gt;</div><div>&gt;&gt; &gt; My standard-parsing fu is weak. =A0Ca=
 n some other folks on this list look at</div><div>&gt;&gt; &gt; this PR, fi=
 gure out what the correct semantics for *fprintf() in this case,</div><div>
 &gt;&gt; &gt; and evaluate the patch? =A0Thanks.</div><div>&gt; [...]</div>=
 <div>&gt;&gt; libc vfprintf currently behaves differently on un|buffered FI=
 LEs with</div><div>&gt;&gt; ferror set:</div><div>&gt;&gt;</div><div>&gt;&g=
 t; 1. Unbuffered FILEs</div>
 <div>&gt;&gt;</div><div>&gt;&gt; =A0 =A0 =A0 -&gt; does not transmit any by=
 tes, and returns -1</div><div>&gt;&gt;</div><div>&gt;&gt; 2. Buffered FILEs=
  (fully buffered, or line buffered)</div><div>&gt;&gt;</div><div>&gt;&gt; =
 =A0 =A0 =A0 -&gt; transmits all bytes, and returns -1</div>
 <div>&gt;&gt;</div><div>&gt;&gt; I believe that this should be reconciled s=
 uch that vfprintf (and all</div><div>&gt;&gt; derivatives) returns sucess|f=
 ailure based on transmission, not taking</div><div>&gt;&gt; ferror state in=
 to account, but an alternate solution would be to reconcile</div>
 <div>&gt;&gt; the behavior of buffered FILEs with the current behavior of u=
 nbuffered</div><div>&gt;&gt; FILEs (e.g. detect ferror state, transmit no b=
 ytes and return -1).</div><div>&gt;</div><div>&gt; I agree with this assess=
 ment. =A0When the error indicator is set on</div>
 <div>&gt; a stream, it means that an error has occurred at some point---not=
 </div><div>&gt; that all subsequent operations on the stream should fail.</=
 div><div>&gt;</div><div>&gt; There ought to be a less ugly fix than the one=
  proposed. =A0Probably</div>
 <div>&gt; the PRINT macro and the various other evil macros in vfprintf()</=
 div><div>&gt; should set ret to EOF, and the following lines in vfprintf.c =
 should</div><div>&gt; be removed:</div><div>&gt;</div><div>&gt; =A0 =A0 =A0=
  =A0if (__sferror(fp))</div>
 <div>&gt; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ret =3D EOF;</div><div>&gt;</div><=
 div>&gt; If vfprintf() is fixed so that printing to a buffered stream</div>=
 <div>&gt; always returns success after a successful write (regardless of th=
 e</div><div>&gt; prior state of the stream&#39;s error indicator), that sho=
 uld fix the</div>
 <div>&gt; problem for unbuffered streams automatically. =A0Unbuffered strea=
 ms</div><div>&gt; go through __sbprintf(), which throws away the output if<=
 /div><div>&gt; vfprintf() returns -1.</div><div><br></div><div>I&#39;ve fol=
 lowed up on David&#39;s suggestion to remove this test and set ret =3D EOF =
 prior to goto error in all relevant places. =A0I audited all cases where __=
 SERR could potentially be set, and determined that all cases are correctly =
 setting __SERR, returning error in the bounding function, and properly goin=
 g to error within __vf(w)printf already (I have an exhaustive list of these=
  if anyone is curious ...). =A0</div>
 <div><br></div><div>Original test program in the PR works with this patch, =
 and the regressions for stdio all function as expected. =A0I took the liber=
 ty of cleaning up a few return -1&#39;s, in favor of return EOF&#39;s. =A0<=
 /div>
 <div><br></div><div>All in all, this is much less ugly than the previous so=
 lution. =A0patch is against head ...</div><br>-- <br>regards,<br>matt<br><b=
 r></div>
 
 --20cf307813d4f19f8804bcb7b556--
 --20cf307813d4f19f8d04bcb7b558
 Content-Type: text/plain; charset=US-ASCII; name="freebsd.PR164674-better.patch.txt"
 Content-Disposition: attachment; 
 	filename="freebsd.PR164674-better.patch.txt"
 Content-Transfer-Encoding: base64
 X-Attachment-Id: f_h0jy3ng60
 
 SW5kZXg6IGxpYi9saWJjL3N0ZGlvL3Zmd3ByaW50Zi5jCj09PT09PT09PT09PT09PT09PT09PT09
 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KLS0tIGxpYi9saWJj
 L3N0ZGlvL3Zmd3ByaW50Zi5jCShyZXZpc2lvbiAyMzM3ODApCisrKyBsaWIvbGliYy9zdGRpby92
 ZndwcmludGYuYwkod29ya2luZyBjb3B5KQpAQCAtNDQ5LDIwICs0NDksMjggQEAKIAogCS8qIEJF
 V0FSRSwgdGhlc2UgYGdvdG8gZXJyb3InIG9uIGVycm9yLiAqLwogI2RlZmluZQlQUklOVChwdHIs
 IGxlbikJZG8gewkJCVwKLQlpZiAoaW9fcHJpbnQoJmlvLCAocHRyKSwgKGxlbiksIGxvY2FsZSkp
 CVwKLQkJZ290byBlcnJvcjsgXAorCWlmIChpb19wcmludCgmaW8sIChwdHIpLCAobGVuKSwgbG9j
 YWxlKSkgewlcCisJCXJldCA9IEVPRjsJXAorCQlnb3RvIGVycm9yOwlcCisJfQlcCiB9IHdoaWxl
 ICgwKQogI2RlZmluZQlQQUQoaG93bWFueSwgd2l0aCkgeyBcCi0JaWYgKGlvX3BhZCgmaW8sICho
 b3dtYW55KSwgKHdpdGgpLCBsb2NhbGUpKSBcCi0JCWdvdG8gZXJyb3I7IFwKKwlpZiAoaW9fcGFk
 KCZpbywgKGhvd21hbnkpLCAod2l0aCksIGxvY2FsZSkpIHsJXAorCQlyZXQgPSBFT0Y7CVwKKwkJ
 Z290byBlcnJvcjsJXAorCX0JXAogfQogI2RlZmluZQlQUklOVEFORFBBRChwLCBlcCwgbGVuLCB3
 aXRoKSB7CVwKLQlpZiAoaW9fcHJpbnRhbmRwYWQoJmlvLCAocCksIChlcCksIChsZW4pLCAod2l0
 aCksIGxvY2FsZSkpIFwKLQkJZ290byBlcnJvcjsgXAorCWlmIChpb19wcmludGFuZHBhZCgmaW8s
 IChwKSwgKGVwKSwgKGxlbiksICh3aXRoKSwgbG9jYWxlKSkgewlcCisJCXJldCA9IEVPRjsJXAor
 CQlnb3RvIGVycm9yOwlcCisJfQlcCiB9CiAjZGVmaW5lCUZMVVNIKCkgeyBcCi0JaWYgKGlvX2Zs
 dXNoKCZpbywgbG9jYWxlKSkgXAotCQlnb3RvIGVycm9yOyBcCisJaWYgKGlvX2ZsdXNoKCZpbywg
 bG9jYWxlKSkgewlcCisJCXJldCA9IEVPRjsJXAorCQlnb3RvIGVycm9yOwlcCisJfQlcCiB9CiAK
 IAkvKgpAQCAtODk3LDYgKzkwNSw3IEBACiAJCQkJCWNvbnZidWYgPSBfX21ic2NvbnYobWJwLCBw
 cmVjKTsKIAkJCQkJaWYgKGNvbnZidWYgPT0gTlVMTCkgewogCQkJCQkJZnAtPl9mbGFncyB8PSBf
 X1NFUlI7CisJCQkJCQlyZXQgPSBFT0Y7CiAJCQkJCQlnb3RvIGVycm9yOwogCQkJCQl9CiAJCQkJ
 CWNwID0gY29udmJ1ZjsKQEAgLTEwMzAsOCArMTAzOSwxMCBAQAogCQkJLyogbGVhZGluZyB6ZXJv
 ZXMgZnJvbSBkZWNpbWFsIHByZWNpc2lvbiAqLwogCQkJUEFEKGRwcmVjIC0gc2l6ZSwgemVyb2Vz
 KTsKIAkJCWlmIChncy5ncm91cGluZykgewotCQkJCWlmIChncm91cGluZ19wcmludCgmZ3MsICZp
 bywgY3AsIGJ1ZitCVUYsIGxvY2FsZSkgPCAwKQorCQkJCWlmIChncm91cGluZ19wcmludCgmZ3Ms
 ICZpbywgY3AsIGJ1ZitCVUYsIGxvY2FsZSkgPCAwKSB7CisJCQkJCXJldCA9IEVPRjsKIAkJCQkJ
 Z290byBlcnJvcjsKKwkJCQl9CiAJCQl9IGVsc2UgewogCQkJCVBSSU5UKGNwLCBzaXplKTsKIAkJ
 CX0KQEAgLTEwNDcsMTAgKzEwNTgsMTEgQEAKIAkJCQkJcHJlYyArPSBleHB0OwogCQkJCX0gZWxz
 ZSB7CiAJCQkJCWlmIChncy5ncm91cGluZykgewotCQkJCQkJbiA9IGdyb3VwaW5nX3ByaW50KCZn
 cywgJmlvLAotCQkJCQkJICAgIGNwLCBjb252YnVmICsgbmRpZywgbG9jYWxlKTsKLQkJCQkJCWlm
 IChuIDwgMCkKKwkJCQkJCWlmICgobiA9IGdyb3VwaW5nX3ByaW50KCZncywgJmlvLAorCQkJCQkJ
 ICAgIGNwLCBjb252YnVmICsgbmRpZywgbG9jYWxlKSkgPCAwKSB7CisJCQkJCQkJcmV0ID0gRU9G
 OwogCQkJCQkJCWdvdG8gZXJyb3I7CisJCQkJCQl9CiAJCQkJCQljcCArPSBuOwogCQkJCQl9IGVs
 c2UgewogCQkJCQkJUFJJTlRBTkRQQUQoY3AsIGNvbnZidWYgKyBuZGlnLApAQCAtMTA4OSw4ICsx
 MTAxLDYgQEAKIAl2YV9lbmQob3JnYXApOwogCWlmIChjb252YnVmICE9IE5VTEwpCiAJCWZyZWUo
 Y29udmJ1Zik7Ci0JaWYgKF9fc2ZlcnJvcihmcCkpCi0JCXJldCA9IEVPRjsKIAlpZiAoKGFyZ3Rh
 YmxlICE9IE5VTEwpICYmIChhcmd0YWJsZSAhPSBzdGF0YXJndGFibGUpKQogCQlmcmVlIChhcmd0
 YWJsZSk7CiAJcmV0dXJuIChyZXQpOwpJbmRleDogbGliL2xpYmMvc3RkaW8vdmZwcmludGYuYwo9
 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
 PT09PT09PT09Ci0tLSBsaWIvbGliYy9zdGRpby92ZnByaW50Zi5jCShyZXZpc2lvbiAyMzM3ODAp
 CisrKyBsaWIvbGliYy9zdGRpby92ZnByaW50Zi5jCSh3b3JraW5nIGNvcHkpCkBAIC0xMjcsNyAr
 MTI3LDcgQEAKIAljb25zdCBDSEFSICpjcDAgPSBjcDsKIAogCWlmIChpb19wcmludGFuZHBhZChp
 b3AsIGNwLCBlcCwgZ3MtPmxlYWQsIHplcm9lcywgbG9jYWxlKSkKLQkJcmV0dXJuICgtMSk7CisJ
 CXJldHVybiAoRU9GKTsKIAljcCArPSBncy0+bGVhZDsKIAl3aGlsZSAoZ3MtPm5zZXBzID4gMCB8
 fCBncy0+bnJlcGVhdHMgPiAwKSB7CiAJCWlmIChncy0+bnJlcGVhdHMgPiAwKQpAQCAtMTM3LDkg
 KzEzNyw5IEBACiAJCQlncy0+bnNlcHMtLTsKIAkJfQogCQlpZiAoaW9fcHJpbnQoaW9wLCBncy0+
 dGhvdXNhbmRzX3NlcCwgZ3MtPnRob3VzZXBfbGVuLCBsb2NhbGUpKQotCQkJcmV0dXJuICgtMSk7
 CisJCQlyZXR1cm4gKEVPRik7CiAJCWlmIChpb19wcmludGFuZHBhZChpb3AsIGNwLCBlcCwgKmdz
 LT5ncm91cGluZywgemVyb2VzLCBsb2NhbGUpKQotCQkJcmV0dXJuICgtMSk7CisJCQlyZXR1cm4g
 KEVPRik7CiAJCWNwICs9ICpncy0+Z3JvdXBpbmc7CiAJfQogCWlmIChjcCA+IGVwKQpAQCAtMzY5
 LDIwICszNjksMjggQEAKIAogCS8qIEJFV0FSRSwgdGhlc2UgYGdvdG8gZXJyb3InIG9uIGVycm9y
 LiAqLwogI2RlZmluZQlQUklOVChwdHIsIGxlbikgeyBcCi0JaWYgKGlvX3ByaW50KCZpbywgKHB0
 ciksIChsZW4pLCBsb2NhbGUpKQlcCi0JCWdvdG8gZXJyb3I7IFwKKwlpZiAoaW9fcHJpbnQoJmlv
 LCAocHRyKSwgKGxlbiksIGxvY2FsZSkpIHsJXAorCQlyZXQgPSBFT0Y7CVwKKwkJZ290byBlcnJv
 cjsJXAorCX0JXAogfQogI2RlZmluZQlQQUQoaG93bWFueSwgd2l0aCkgeyBcCi0JaWYgKGlvX3Bh
 ZCgmaW8sIChob3dtYW55KSwgKHdpdGgpLCBsb2NhbGUpKSBcCisJaWYgKGlvX3BhZCgmaW8sICho
 b3dtYW55KSwgKHdpdGgpLCBsb2NhbGUpKSB7CVwKKwkJcmV0ID0gRU9GOwlcCiAJCWdvdG8gZXJy
 b3I7IFwKKwl9CVwKIH0KICNkZWZpbmUJUFJJTlRBTkRQQUQocCwgZXAsIGxlbiwgd2l0aCkgewlc
 Ci0JaWYgKGlvX3ByaW50YW5kcGFkKCZpbywgKHApLCAoZXApLCAobGVuKSwgKHdpdGgpLCBsb2Nh
 bGUpKSBcCi0JCWdvdG8gZXJyb3I7IFwKKwlpZiAoaW9fcHJpbnRhbmRwYWQoJmlvLCAocCksIChl
 cCksIChsZW4pLCAod2l0aCksIGxvY2FsZSkpIHsJXAorCQlyZXQgPSBFT0Y7CVwKKwkJZ290byBl
 cnJvcjsJXAorCX0JXAogfQogI2RlZmluZQlGTFVTSCgpIHsgXAotCWlmIChpb19mbHVzaCgmaW8s
 IGxvY2FsZSkpIFwKKwlpZiAoaW9fZmx1c2goJmlvLCBsb2NhbGUpKSB7CVwKKwkJcmV0ID0gRU9G
 OwlcCiAJCWdvdG8gZXJyb3I7IFwKKwl9CVwKIH0KIAogCS8qCkBAIC02MTcsNiArNjI1LDcgQEAK
 IAkJCQkgICAgKHdjaGFyX3QpR0VUQVJHKHdpbnRfdCksICZtYnMpOwogCQkJCWlmIChtYnNlcWxl
 biA9PSAoc2l6ZV90KS0xKSB7CiAJCQkJCWZwLT5fZmxhZ3MgfD0gX19TRVJSOworCQkJCQlyZXQg
 PSBFT0Y7CiAJCQkJCWdvdG8gZXJyb3I7CiAJCQkJfQogCQkJCXNpemUgPSAoaW50KW1ic2VxbGVu
 OwpAQCAtODI4LDYgKzgzNyw3IEBACiAJCQkJCWNvbnZidWYgPSBfX3djc2NvbnYod2NwLCBwcmVj
 KTsKIAkJCQkJaWYgKGNvbnZidWYgPT0gTlVMTCkgewogCQkJCQkJZnAtPl9mbGFncyB8PSBfX1NF
 UlI7CisJCQkJCQlyZXQgPSBFT0Y7CiAJCQkJCQlnb3RvIGVycm9yOwogCQkJCQl9CiAJCQkJCWNw
 ID0gY29udmJ1ZjsKQEAgLTk2Miw4ICs5NzIsMTAgQEAKIAkJCS8qIGxlYWRpbmcgemVyb2VzIGZy
 b20gZGVjaW1hbCBwcmVjaXNpb24gKi8KIAkJCVBBRChkcHJlYyAtIHNpemUsIHplcm9lcyk7CiAJ
 CQlpZiAoZ3MuZ3JvdXBpbmcpIHsKLQkJCQlpZiAoZ3JvdXBpbmdfcHJpbnQoJmdzLCAmaW8sIGNw
 LCBidWYrQlVGLCBsb2NhbGUpIDwgMCkKKwkJCQlpZiAoZ3JvdXBpbmdfcHJpbnQoJmdzLCAmaW8s
 IGNwLCBidWYrQlVGLCBsb2NhbGUpIDwgMCkgeworCQkJCQlyZXQgPSBFT0Y7CiAJCQkJCWdvdG8g
 ZXJyb3I7CisJCQkJfQogCQkJfSBlbHNlIHsKIAkJCQlQUklOVChjcCwgc2l6ZSk7CiAJCQl9CkBA
 IC05NzksMTAgKzk5MSwxMSBAQAogCQkJCQlwcmVjICs9IGV4cHQ7CiAJCQkJfSBlbHNlIHsKIAkJ
 CQkJaWYgKGdzLmdyb3VwaW5nKSB7Ci0JCQkJCQluID0gZ3JvdXBpbmdfcHJpbnQoJmdzLCAmaW8s
 Ci0JCQkJCQkgICAgY3AsIGR0b2FlbmQsIGxvY2FsZSk7Ci0JCQkJCQlpZiAobiA8IDApCisJCQkJ
 CQlpZiAoKG4gPSBncm91cGluZ19wcmludCgmZ3MsICZpbywKKwkJCQkJCSAgICBjcCwgZHRvYWVu
 ZCwgbG9jYWxlKSkgPCAwKSB7CisJCQkJCQkJcmV0ID0gRU9GOwogCQkJCQkJCWdvdG8gZXJyb3I7
 CisJCQkJCQl9CiAJCQkJCQljcCArPSBuOwogCQkJCQl9IGVsc2UgewogCQkJCQkJUFJJTlRBTkRQ
 QUQoY3AsIGR0b2FlbmQsCkBAIC0xMDI0LDggKzEwMzcsNiBAQAogI2VuZGlmCiAJaWYgKGNvbnZi
 dWYgIT0gTlVMTCkKIAkJZnJlZShjb252YnVmKTsKLQlpZiAoX19zZmVycm9yKGZwKSkKLQkJcmV0
 ID0gRU9GOwogCWlmICgoYXJndGFibGUgIT0gTlVMTCkgJiYgKGFyZ3RhYmxlICE9IHN0YXRhcmd0
 YWJsZSkpCiAJCWZyZWUgKGFyZ3RhYmxlKTsKIAlyZXR1cm4gKHJldCk7Cg==
 --20cf307813d4f19f8d04bcb7b558--
>Unformatted:
