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

NetBSD Home
NetBSD PR Database Search

(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.