From owner-freebsd-bugs@FreeBSD.ORG Sun Aug 16 03:50:02 2009 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A34EA106568C for ; Sun, 16 Aug 2009 03:50:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 7CF938FC45 for ; Sun, 16 Aug 2009 03:50:02 +0000 (UTC) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.3/8.14.3) with ESMTP id n7G3o1rh046797 for ; Sun, 16 Aug 2009 03:50:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.3/8.14.3/Submit) id n7G3o1f6046796; Sun, 16 Aug 2009 03:50:01 GMT (envelope-from gnats) Resent-Date: Sun, 16 Aug 2009 03:50:01 GMT Resent-Message-Id: <200908160350.n7G3o1f6046796@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Eric Blake Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6085E106568B for ; Sun, 16 Aug 2009 03:47:32 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21]) by mx1.freebsd.org (Postfix) with ESMTP id 4FA258FC3F for ; Sun, 16 Aug 2009 03:47:32 +0000 (UTC) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.14.3/8.14.3) with ESMTP id n7G3lVSc081938 for ; Sun, 16 Aug 2009 03:47:31 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.3/8.14.3/Submit) id n7G3lVRs081937; Sun, 16 Aug 2009 03:47:31 GMT (envelope-from nobody) Message-Id: <200908160347.n7G3lVRs081937@www.freebsd.org> Date: Sun, 16 Aug 2009 03:47:31 GMT From: Eric Blake To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: misc/137819: fpurge violates stdio invariant X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 16 Aug 2009 03:50:02 -0000 >Number: 137819 >Category: misc >Synopsis: fpurge violates stdio invariant >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: Sun Aug 16 03:50:00 UTC 2009 >Closed-Date: >Last-Modified: >Originator: Eric Blake >Release: 6.1 >Organization: N/A >Environment: FreeBSD freebsd6 6.1-RELEASE FreeBSD 6.1-RELEASE #0: Sun May 7 04:42:56 UTC 2006 root@opus.cse.buffalo.edu:/usr/obj/usr/src/sys/SMP i386 >Description: According to the stdio source code, all streams must meet the invariant that if a stream is open for both reading and writing, then _w is 0 if the stream is not currently writing. If this invariant is violated, then code like putc will misbehave, and fflush will not realize that there is data to be written. Unfortunately, fpurge blindly sets _w to non-zero even on read-write file streams where pending read data was flushed. This in turn requires the gnulib fpurge module to write a wrapper around fpurge and poke at FILE internals in a number of GNU projects. >How-To-Repeat: $ cat foo.c #include #include int main (int argc, char **argv) { FILE *f = fopen("bar", "w+"); fputs ("abc", f); rewind (f); while (EOF != fgetc (f)); fpurge (f); /* Nothing to purge, but stream state now corrupted. */ argc > 1 ? putc ('d', f) : fputc ('d', f); return 0; } $ ./foo $ cat bar && echo abc $ ./foo 1 $ cat bar && echo abc Expected behavior - both './foo' and './foo 1' should set the contents of bar to "abcd". However, fpurge mistakenly set the _w member to nonzero, while leaving the __SRD flag set (rather than setting the __SWR flag), such that subsequent putc use the buffer without kicking the stream over to write mode, and the implicit fflush/fclose at program exit see that the stream is in read mode and assume that nothing needs to be flushed. >Fix: In fpurge.c, replace this line: fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : fp->_bf._size; with: fp->_w = fp->_flags & (__SLBF|__SNBF|__SRD) ? 0 : fp->_bf._size; >Release-Note: >Audit-Trail: >Unformatted: