Safe coding practices (was Re: Bug in users command)

Chris Torek torek at h2opolo.ee.lbl.gov
Fri Feb 8 12:41:06 AEST 1991


I posted two articles early this morning (<9644 at dog.ee.lbl.gov> and
<9653 at dog.ee.lbl.gov>) with the second being a correction to the first.
Now that article cancellation is fixed, here is a corrected version;
I have cancelled the previous two articles.

Before things get out of hand, here is the fgetline man page from
4.3-and-two-thirds-or-whatever-you-call-it:

   FGETLINE(3)         UNIX Programmer's Manual          FGETLINE(3)

   NAME
	fgetline - get a line from a stream

   SYNOPSIS
	#include <stdio.h>

	char *
	fgetline(FILE *stream, int *len);

   DESCRIPTION
	Fgetline returns a pointer to the next line from the stream
	pointed to by stream.  The newline character at the end of
	the line is replaced by a '\0' character.

	If len is non-NULL, the length of the line, not counting the
	terminating NUL, is stored in the memory location it refer-
	ences.

   SEE ALSO
	ferror(3), fgets(3), fopen(3), putc(3)

   RETURN VALUE
	Upon successful completion a pointer is returned; this
	pointer becomes invalid after the next I/O operation on
	stream (whether successful or not) or as soon as the stream
	is closed.  Otherwise, NULL is returned.  Fgetline does not
	distinguish between end-of-file and error, and callers must
	use feof and ferror to determine which occurred.  If an
	error occurrs, the global variable errno is set to indicate
	the error.  The end-of-file condition is remembered, even on
	a terminal, and all subsequent attempts to read will return
	NULL until the condition is cleared with clearerr.

	It is not possible to tell whether the final line of an
	input file was terminated with a newline.

   ERRORS
	[EBADF]        Stream is not a stream open for reading.

	Fgetline may also fail and set errno for any of the errors
	specified for the routines fflush(3), malloc(3), read(2),
	stat(2), or realloc(3).

(the underlining and boldface have vanished, but the above should still
be comprehensible).

Note that fgetline makes no promises about the pointer it returns.  If
you want a copy of the line, you must copy it yourself.  This is so that
fgetline can return pointers within the original stdio buffers; in
particular, the sequence:

	/* add quote widgets */
	while ((p = fgetline(inf, (int *)NULL)) != NULL)
		if (fprintf(outf, ">%s\n", p) < 0)	/* error */
			break;

does not require an intermediate buffer into which lines are copied.
They go directly from the input file's buffer to the output file's
buffer.  (Thus, there is one memory-to-memory copy in the above loop.)

It is unfortunate that there is no formal mechanism to avoid read
copies for other operations.  In particular, copying an input file to
an output file could be done with no (user) memory-to-memory copies
with a loop of the form:

	while (there is more in the input buffer)
		write the input buffer to the output file;

whenever the block sizes match, since the input buffer can be written
to the output file with a direct write() system call.  As it is, you
must use fread to obtain data, with at least one copy.

[Thanks to: Arnold Robbins, Cesar A Quiroz, Jef Poskanzer, Henry
Spencer, and Ray Butterworth for the fixes included here.  (These are
in alphabetical order, by first name.)]
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427)
Berkeley, CA		Domain:	torek at ee.lbl.gov



More information about the Comp.bugs.4bsd.ucb-fixes mailing list