NetBSD Problem Report #41992
From www@NetBSD.org Fri Sep 4 23:25:27 2009
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
by www.NetBSD.org (Postfix) with ESMTP id 5CF8363BCFB
for <gnats-bugs@gnats.netbsd.org>; Fri, 4 Sep 2009 23:25:27 +0000 (UTC)
Message-Id: <20090904232527.153DA63BC8C@www.NetBSD.org>
Date: Fri, 4 Sep 2009 23:25:27 +0000 (UTC)
From: kate@tendra.org
Reply-To: kate@tendra.org
To: gnats-bugs@NetBSD.org
Subject: fgets returns non-NULL for a buffer size of 1 on an empty file
X-Send-Pr-Version: www-1.0
>Number: 41992
>Category: standards
>Synopsis: fgets returns non-NULL for a buffer size of 1 on an empty file
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kleink
>State: closed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Sep 04 23:30:00 +0000 2009
>Closed-Date: Sat Oct 24 14:52:20 +0000 2009
>Last-Modified: Sat Oct 24 14:55:01 +0000 2009
>Originator: Kate F
>Release: 3.1
>Organization:
>Environment:
NetBSD clarion 3.1 NetBSD 3.1 (GENERIC) #0: Tue Oct 31 04:27:07 UTC 2006 builds@b0.netbsd.org:/home/builds/ab/netbsd-3-1-RELEASE/i386/200610302053Z-obj/home/builds/ab/netbsd-3-1-RELEASE/src/sys/arch/i386/compile/GENERIC i386
>Description:
Here's a test case:
#include <stdio.h>
int main(void)
{
FILE *f;
char *p;
char a[1];
/* create an empty file. x should not exist beforehand */
system("touch x");
f = fopen("x", "r");
if (f == NULL) {
perror("fopen");
return 1;
}
p = fgets(a, sizeof a, f);
if (p == NULL) {
perror("fgets");
return 1;
}
/* i believe p should be NULL for an empty file where sizeof a is 1 */
printf("p = %p\n", p);
return 0;
}
The wording for C differs slightly from the wording for POSIX for fgets in this situation, but both are at EOF, so I believe both ought to return NULL.
This bug was described to me by Magnus Loef <magnus-swe@telia.com>, in ##c on freenode. He points out that this behaviour has the undesirable effect of causing infinite loops on empty files for the ubiquitous while (fgets(...) != NULL) ...; idiom.
>How-To-Repeat:
>Fix:
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: lib-bug-people->kleink
Responsible-Changed-By: joerg@NetBSD.org
Responsible-Changed-When: Fri, 04 Sep 2009 23:35:04 +0000
Responsible-Changed-Why:
Local standards guru.
The behavior required by POSIX is questionable for the case of empty
buffer. Implementing the requirement for size=1 would require reading
from the stream, even though no input will be consumed. This can have
undesirable effects e.g. for pipes.
Looking at the implementation, the return value of NULL for size=0 also
seems questionable.
Can you clarify if both of this is intentional and the correct behavior?
From: David Laight <david@l8s.co.uk>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: standards/41992 (fgets returns non-NULL for a buffer size of 1 on an empty file)
Date: Mon, 12 Oct 2009 22:39:38 +0100
On Fri, Sep 04, 2009 at 11:35:05PM +0000, joerg@NetBSD.org wrote:
> The behavior required by POSIX is questionable for the case of empty
> buffer. Implementing the requirement for size=1 would require reading
> from the stream, even though no input will be consumed. This can have
> undesirable effects e.g. for pipes.
I'm not sure that reading from the stream (into the stdio buffer)
can be a problem.
Programs using stdio cannot control the offset of the underlying file.
David
--
David Laight: david@l8s.co.uk
From: David Laight <dsl@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/41992 CVS commit: src/lib/libc/stdio
Date: Wed, 14 Oct 2009 21:25:52 +0000
Module Name: src
Committed By: dsl
Date: Wed Oct 14 21:25:52 UTC 2009
Modified Files:
src/lib/libc/stdio: fgets.c vfprintf.c
Log Message:
Change a while () {} into a do {} while() so that fgets(buf, 1, file)
detects EOF on an empty file.
Fixes most of PR/41992
To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/lib/libc/stdio/fgets.c
cvs rdiff -u -r1.57 -r1.58 src/lib/libc/stdio/vfprintf.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
State-Changed-From-To: open->closed
State-Changed-By: dsl@NetBSD.org
State-Changed-When: Sat, 24 Oct 2009 14:52:20 +0000
State-Changed-Why:
Code has been changed to return EOF before buffer length errors.
Howver I suspect the originator isn't using this code at all - but glibc!
From: David Laight <dsl@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/41992 CVS commit: src/lib/libc/stdio
Date: Sat, 24 Oct 2009 14:50:49 +0000
Module Name: src
Committed By: dsl
Date: Sat Oct 24 14:50:48 UTC 2009
Modified Files:
src/lib/libc/stdio: fgets.c
Log Message:
Check for EOF before erroring fgets() with length <= 0.
If length is invalid, set errno = EINVAL and __SERR as well returning NULL.
Should let me close PR/41992.
To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/lib/libc/stdio/fgets.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
>Unformatted:
joerg
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.