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,