Module Name:    src
Committed By:   roy
Date:           Thu Sep 24 20:38:53 UTC 2009

Modified Files:
        src/lib/libc/stdio: fgetln.c fgetstr.c fgetwln.c getdelim.c local.h

Log Message:
__getdelim works on strings up to SIZE_MAX - 2 and returns 0 on EOF.
getdelim works on strings up to SSIZE_MAX and returns -1 on EOF.
__fgetstr is now just a wrapper around __getdelim and ensures that
the buffer doesn't overflow the one provided by FILE.
__slbexpand is now static in fgetwln as it is the only consumer of that func.


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/lib/libc/stdio/fgetln.c
cvs rdiff -u -r1.5 -r1.6 src/lib/libc/stdio/fgetstr.c
cvs rdiff -u -r1.2 -r1.3 src/lib/libc/stdio/fgetwln.c
cvs rdiff -u -r1.3 -r1.4 src/lib/libc/stdio/getdelim.c
cvs rdiff -u -r1.20 -r1.21 src/lib/libc/stdio/local.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/stdio/fgetln.c
diff -u src/lib/libc/stdio/fgetln.c:1.14 src/lib/libc/stdio/fgetln.c:1.15
--- src/lib/libc/stdio/fgetln.c:1.14	Mon May 10 16:47:11 2004
+++ src/lib/libc/stdio/fgetln.c	Thu Sep 24 20:38:53 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: fgetln.c,v 1.14 2004/05/10 16:47:11 drochner Exp $	*/
+/*	$NetBSD: fgetln.c,v 1.15 2009/09/24 20:38:53 roy Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)fgetline.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: fgetln.c,v 1.14 2004/05/10 16:47:11 drochner Exp $");
+__RCSID("$NetBSD: fgetln.c,v 1.15 2009/09/24 20:38:53 roy Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -64,10 +64,6 @@
 	FILE *fp;
 	size_t *lenp;
 {
-	char *cp;
-
-	FLOCKFILE(fp);
-	cp = __fgetstr(fp, lenp, '\n');
-	FUNLOCKFILE(fp);
-	return cp;
+	
+	return __fgetstr(fp, lenp, '\n');
 }

Index: src/lib/libc/stdio/fgetstr.c
diff -u src/lib/libc/stdio/fgetstr.c:1.5 src/lib/libc/stdio/fgetstr.c:1.6
--- src/lib/libc/stdio/fgetstr.c:1.5	Sat Jan 31 06:14:13 2009
+++ src/lib/libc/stdio/fgetstr.c	Thu Sep 24 20:38:53 2009
@@ -1,11 +1,10 @@
-/*	$NetBSD: fgetstr.c,v 1.5 2009/01/31 06:14:13 lukem Exp $	*/
+/* $NetBSD: fgetstr.c,v 1.6 2009/09/24 20:38:53 roy Exp $	*/
 
-/*-
- * Copyright (c) 1990, 1993
- *	The Regents of the University of California.  All rights reserved.
+/*
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
  *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Roy Marples.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -15,160 +14,60 @@
  * 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.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
  *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
  */
 
 #include <sys/cdefs.h>
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char sccsid[] = "@(#)fgetline.c	8.1 (Berkeley) 6/4/93";
-#else
-__RCSID("$NetBSD: fgetstr.c,v 1.5 2009/01/31 06:14:13 lukem Exp $");
-#endif
-#endif /* LIBC_SCCS and not lint */
+__RCSID("$NetBSD: fgetstr.c,v 1.6 2009/09/24 20:38:53 roy Exp $");
 
 #include "namespace.h"
 
 #include <assert.h>
+#include <errno.h>
+#include <limits.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+
 #include "reentrant.h"
 #include "local.h"
 
 /*
- * Expand the line buffer.  Return -1 on error.
-#ifdef notdef
- * The `new size' does not account for a terminating '\0',
- * so we add 1 here.
-#endif
- */
-int
-__slbexpand(fp, newsize)
-	FILE *fp;
-	size_t newsize;
-{
-	void *p;
-
-#ifdef notdef
-	++newsize;
-#endif
-	_DIAGASSERT(fp != NULL);
-
-	if ((size_t)fp->_lb._size >= newsize)
-		return (0);
-	if ((p = realloc(fp->_lb._base, newsize)) == NULL)
-		return (-1);
-	fp->_lb._base = p;
-	fp->_lb._size = newsize;
-	return (0);
-}
-
-/*
- * Get an input line.  The returned pointer often (but not always)
- * points into a stdio buffer.  Fgetline does not alter the text of
- * the returned line (which is thus not a C string because it will
- * not necessarily end with '\0'), but does allow callers to modify
- * it if they wish.  Thus, we set __SMOD in case the caller does.
+ * Get an input line.
+ * This now uses getdelim(3) for a code reduction.
+ * The upside is that strings are now always NULL terminated, but relying
+ * on this is non portable - better to use the POSIX getdelim(3) function.
  */
 char *
-__fgetstr(fp, lenp, sep)
-	FILE *fp;
-	size_t *lenp;
-	int sep;
+__fgetstr(FILE *__restrict fp, size_t *__restrict lenp, int sep)
 {
-	unsigned char *p;
-	size_t len;
-	size_t off;
+	char *p;
+	size_t size;
 
 	_DIAGASSERT(fp != NULL);
 	_DIAGASSERT(lenp != NULL);
 
-	/* make sure there is input */
-	if (fp->_r <= 0 && __srefill(fp)) {
-		*lenp = 0;
-		return (NULL);
-	}
-
-	/* look for a newline in the input */
-	if ((p = memchr((void *)fp->_p, sep, (size_t)fp->_r)) != NULL) {
-		char *ret;
-
-		/*
-		 * Found one.  Flag buffer as modified to keep fseek from
-		 * `optimising' a backward seek, in case the user stomps on
-		 * the text.
-		 */
-		p++;		/* advance over it */
-		ret = (char *)fp->_p;
-		*lenp = len = p - fp->_p;
-		fp->_flags |= __SMOD;
-		fp->_r -= len;
-		fp->_p = p;
-		return (ret);
+	p = (char *)fp->_lb._base;
+	size = fp->_lb._size;
+	*lenp = __getdelim(&p, &size, sep, fp);
+	/* The struct size variable is only an int ..... */
+	if (size > INT_MAX) {
+		fp->_lb._size = INT_MAX;
+		errno = EOVERFLOW;
+		goto error;
 	}
-
-	/*
-	 * We have to copy the current buffered data to the line buffer.
-	 * As a bonus, though, we can leave off the __SMOD.
-	 *
-	 * OPTIMISTIC is length that we (optimistically) expect will
-	 * accommodate the `rest' of the string, on each trip through the
-	 * loop below.
-	 */
-#define OPTIMISTIC 80
-
-	for (len = fp->_r, off = 0;; len += fp->_r) {
-		size_t diff;
-
-		/*
-		 * Make sure there is room for more bytes.  Copy data from
-		 * file buffer to line buffer, refill file and look for
-		 * newline.  The loop stops only when we find a newline.
-		 */
-		if (__slbexpand(fp, len + OPTIMISTIC))
-			goto error;
-		(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
-		    len - off);
-		off = len;
-		if (__srefill(fp))
-			break;	/* EOF or error: return partial line */
-		if ((p = memchr((void *)fp->_p, sep, (size_t)fp->_r)) == NULL)
-			continue;
-
-		/* got it: finish up the line (like code above) */
-		p++;
-		diff = p - fp->_p;
-		len += diff;
-		if (__slbexpand(fp, len))
-			goto error;
-		(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
-		    diff);
-		fp->_r -= diff;
-		fp->_p = p;
-		break;
-	}
-	*lenp = len;
-#ifdef notdef
-	fp->_lb._base[len] = 0;
-#endif
-	return ((char *)fp->_lb._base);
-
+	fp->_lb._size = (int)size;
+	if (*lenp < SIZE_MAX)
+		return p;
 error:
-	*lenp = 0;		/* ??? */
-	return (NULL);		/* ??? */
+	*lenp = 0;
+	return NULL;
 }

Index: src/lib/libc/stdio/fgetwln.c
diff -u src/lib/libc/stdio/fgetwln.c:1.2 src/lib/libc/stdio/fgetwln.c:1.3
--- src/lib/libc/stdio/fgetwln.c:1.2	Sat Jan 31 06:08:28 2009
+++ src/lib/libc/stdio/fgetwln.c	Thu Sep 24 20:38:53 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: fgetwln.c,v 1.2 2009/01/31 06:08:28 lukem Exp $	*/
+/*	$NetBSD: fgetwln.c,v 1.3 2009/09/24 20:38:53 roy Exp $	*/
 
 /*-
  * Copyright (c) 2002-2004 Tim J. Robbins.
@@ -31,12 +31,16 @@
 #if 0
 __FBSDID("$FreeBSD: src/lib/libc/stdio/fgetwln.c,v 1.2 2004/08/06 17:00:09 tjr Exp $");
 #else
-__RCSID("$NetBSD: fgetwln.c,v 1.2 2009/01/31 06:08:28 lukem Exp $");
+__RCSID("$NetBSD: fgetwln.c,v 1.3 2009/09/24 20:38:53 roy Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
 #include "namespace.h"
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <wchar.h>
 #include "reentrant.h"
 #include "local.h"
@@ -45,6 +49,37 @@
 __weak_alias(fgetwln,_fgetwln)
 #endif
 
+/*
+ * Expand the line buffer.  Return -1 on error.
+#ifdef notdef
+ * The `new size' does not account for a terminating '\0',
+ * so we add 1 here.
+#endif
+ */
+static int
+__slbexpand(FILE *fp, size_t newsize)
+{
+	void *p;
+
+#ifdef notdef
+	++newsize;
+#endif
+	_DIAGASSERT(fp != NULL);
+
+	/* fp->_lb._size is an int ..... */
+	if (newsize > INT_MAX) {
+		errno = EOVERFLOW;
+		return (-1);
+	}
+	if ((size_t)fp->_lb._size >= newsize)
+		return (0);
+	if ((p = realloc(fp->_lb._base, newsize)) == NULL)
+		return (-1);
+	fp->_lb._base = p;
+	fp->_lb._size = newsize;
+	return (0);
+}
+
 wchar_t *
 fgetwln(FILE * __restrict fp, size_t *lenp)
 {

Index: src/lib/libc/stdio/getdelim.c
diff -u src/lib/libc/stdio/getdelim.c:1.3 src/lib/libc/stdio/getdelim.c:1.4
--- src/lib/libc/stdio/getdelim.c:1.3	Tue Jul 14 18:29:41 2009
+++ src/lib/libc/stdio/getdelim.c	Thu Sep 24 20:38:53 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: getdelim.c,v 1.3 2009/07/14 18:29:41 roy Exp $ */
+/* $NetBSD: getdelim.c,v 1.4 2009/09/24 20:38:53 roy Exp $ */
 
 /*
  * Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -28,7 +28,9 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: getdelim.c,v 1.3 2009/07/14 18:29:41 roy Exp $");
+__RCSID("$NetBSD: getdelim.c,v 1.4 2009/09/24 20:38:53 roy Exp $");
+
+#include "namespace.h"
 
 #include <sys/param.h>
 
@@ -47,12 +49,15 @@
  * without the need for a realloc. */
 #define MINBUF	128
 
+/* This private function allows strings of upto SIZE_MAX - 2
+ * and returns 0 on EOF, both of which are disallowed by POSIX.
+ * Maybe this should be named fgetdelim and proposed to the OpenGroup....*/
 ssize_t
-getdelim(char **__restrict buf, size_t *__restrict buflen,
+__getdelim(char **__restrict buf, size_t *__restrict buflen,
     int sep, FILE *__restrict fp)
 {
 	unsigned char *p;
-	size_t len, off, newlen;
+	size_t len, newlen, off;
 	char *newb;
 
 	_DIAGASSERT(fp != NULL);
@@ -72,8 +77,7 @@
 	for (;;) {
 		/* If the input buffer is empty, refill it */
 		if (fp->_r <= 0 && __srefill(fp)) {
-			/* POSIX requires we return -1 on EOF */
-			if (off == 0 || __sferror(fp))
+			if (__sferror(fp))
 				goto error;
 			break;
 		}
@@ -85,13 +89,12 @@
 		else
 			len = (p - fp->_p) + 1;
 
-		newlen = off + len;
-		/* Ensure that the resultant buffer length fits in ssize_t */
-		if (newlen > (size_t)SSIZE_MAX) {
+		newlen = off + len + 1;
+		/* Ensure we can handle it */
+		if (newlen < off || newlen > SIZE_MAX - 2) {
 			errno = EOVERFLOW;
 			goto error;
 		}
-		newlen++; /* reserve space for the NULL terminator */
 		if (newlen > *buflen) {
 			if (newlen < MINBUF)
 				newlen = MINBUF;
@@ -133,3 +136,21 @@
 	FUNLOCKFILE(fp);
 	return -1;
 }
+
+ssize_t
+getdelim(char **__restrict buf, size_t *__restrict buflen,
+    int sep, FILE *__restrict fp)
+{
+	ssize_t len;
+
+	len = __getdelim(buf, buflen, sep, fp);
+	if (len == 0) {
+		/* POSIX requires that we return -1 on EOF */
+		return -1;
+	} else if (len < -1) {
+		/* POSIX requires no string larger than SSIZE_MAX */
+		errno = EOVERFLOW;
+		return -1;
+	}
+	return len;
+}

Index: src/lib/libc/stdio/local.h
diff -u src/lib/libc/stdio/local.h:1.20 src/lib/libc/stdio/local.h:1.21
--- src/lib/libc/stdio/local.h:1.20	Sat May 14 23:51:02 2005
+++ src/lib/libc/stdio/local.h	Thu Sep 24 20:38:53 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: local.h,v 1.20 2005/05/14 23:51:02 christos Exp $	*/
+/*	$NetBSD: local.h,v 1.21 2009/09/24 20:38:53 roy Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -75,8 +75,9 @@
 extern wint_t	__fgetwc_unlock __P((FILE *));
 extern wint_t	__fputwc_unlock __P((wchar_t, FILE *));
 
+extern ssize_t	__getdelim __P((char ** __restrict, size_t * __restrict, int,
+    FILE * __restrict));
 extern char	*__fgetstr __P((FILE * __restrict, size_t * __restrict, int));
-extern int	 __slbexpand __P((FILE *, size_t));
 extern int 	 __vfwprintf_unlocked __P((FILE *, const wchar_t *,
     _BSD_VA_LIST_));
 extern int	 __vfwscanf_unlocked __P((FILE * __restrict,

Reply via email to