*BSD News Article 34137


Return to BSD News archive

Xref: sserve comp.os.386bsd.questions:12253 comp.os.386bsd.development:2373 comp.os.386bsd.misc:3141
Path: sserve!newshost.anu.edu.au!harbinger.cc.monash.edu.au!bunyip.cc.uq.oz.au!munnari.oz.au!constellation!convex!convex!cs.utexas.edu!swrinde!emory!nntp.msstate.edu!nntp.memphis.edu!nntp.rhodes.edu!zen.mathcs.rhodes.edu!stuart
Newsgroups: comp.os.386bsd.questions,comp.os.386bsd.development,comp.os.386bsd.misc
Subject: Re: Why does FreeBSD 1.1.5 say gets() is unsafe?
Message-ID: <1994Aug10.151130.1017@rhodes>
From: stuart@zen.mathcs.rhodes.edu (Brian L. Stuart)
Date: 10 Aug 94 15:11:29 -0500
References: <30lrf3$2ii@acmez.gatech.edu> <311m2e$o33@agate.berkeley.edu>  
 <324v1b$14g@boavista.bln.sub.org>
Distribution: world
Nntp-Posting-Host: zen.mathcs.rhodes.edu
Lines: 79

In article <324v1b$14g@boavista.bln.sub.org>, erdmann@boavista.bln.sub.org (Michael Erdmann) writes:
|> In article <CturD6.3C1@cs.vu.nl>, kjb@cs.vu.nl (Kees J. Bot) writes:
|> |> 
|> |> I personally don't use gets() or fgets() ever.  Typical example of my
|> |> code attached below.  (allocate() and fatal() are left to your
|> |> imagination.)
|> |> --
|> 
|> 2. The function read1line
|> -------------------------
|> I have to agree with Kees J. Bot, i am using also some function like
|> he has given with some slight changes:
|> 
|> 1. The allocation stratagy was to expensive. Allways when the string
|>    was reallocated twice the current size was allocated leaving lots
|>    of unused memory in the return string (but how cares these days). 
|> 
|>    I have introduced an intermediate buffer which is dynmicaly 
|>    increased by a fixed  increment. 
|>    And the final string is returned via strdup.
|> 
|> char *read1line(FILE *fp)
|> /* Read one line from a file.  Result is a malloc()'d string or NULL for EOF */
|> {
|> 	static char *line = NULL;
|>         size_t  lineLength=80;
|> 	size_t idx;
|> 	int c;
|> 
|>         if( line ==NULL )
|> 	   line = malloc(lineLength*sizeof(char));
|>         
|> 	for(idx=0; (c= getc(fp)) != EOF && c != '\n'; ++idx) {
|> 	    if (idx == lineLength ) {
|> 		lineLength += lineLength ;
|> 		line= realloc(line, lineLength*sizeof(char));
|> 	    }
|> 	    line[idx]= c;
|> 	}
|> ...

At the risk of picking an excessively fine nit (and mixing my metaphors),
a good argument can be made for doubling the size of the array rather
than adding a fixed amount.  realloc() may need to copy the previously
allocated block to a position with enough free space.  So realloc()ing
a block previously of size k will take O(k) time (big-O, of course, implies
that we're talking worst case).  If we ultimately need n bytes, then
doubling will lead to ln n realloc()s and the sum up to ln n of 2^k
is O(n).  Adding a constant amount leads to O(n) realloc()s and the sum
is O(n^2).  It is true that doubling will lead to waste bounded by n
whereas adding a fixed amount bounds the waste by the increment.  It
seems to be the classic time vs. space tradeoff.  Since I'm using O(n)
space anyway, I tend to use the doubling approach.  On top of that, I
like to pick my initial size to be a little bigger than the expected
size.  That way, in the typical case, there's no copying and very
little wasted space.

|> 2. Upon EOF the function schould not check for the error. This should
|>    allways be done by the caller, because only he knows what to do 
|>    in case of an error.

On this one, it depends.  If this code is in a layer that is used in several
applications, then yes the error should be passed on up.  On the other hand
if it is in an application specific library layer, then handling the error
here amortizes the error handling development across all uses in the application
suite.  I find this technique useful in both places and not just in regards
to gets(), but for any array I don't know at compile time.  Since becoming the
nth (where n is large) person to discover this for himself, I find I don't
use linked lists nearly as often.  They still have their uses, of course,
but you don't need them just to get around setting compile time limits
on linear structures.

Forgive me for letting the academic in me out for a while.  He's been
suitably disciplined and shouldn't bother you again :-)

Brian L. Stuart
Math/CS Dept, Rhodes College, Memphis, TN  38112
stuart@mathcs.rhodes.edu