From decwrl!labrea!rutgers!tut.cis.ohio-state.edu!cwjcc!hal!ncoast!allbery Fri Nov 18 20:44:54 PST 1988 Article 730 of comp.sources.misc: Path: granite!decwrl!labrea!rutgers!tut.cis.ohio-state.edu!cwjcc!hal!ncoast!allbery From: ok@quintus.UUCP Newsgroups: comp.sources.misc Subject: v05i053: A "safe" replacement for gets() Message-ID: <674@quintus.UUCP> Date: 15 Nov 88 23:28:26 GMT Sender: allbery@ncoast.UUCP Reply-To: ok@quintus.UUCP Organization: Quintus Computer Systems, Inc. Lines: 123 Approved: allbery@ncoast.UUCP Posting-number: Volume 5, Issue 53 Submitted-by: "A. Nonymous" Archive-name: getsafe [Aaaaagh. I always suspected gets() was a potential bomb. How about #define gets(s) fgets(s, sizeof s, stdin) as a quick fix? ++bsa] #!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting test in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # getsafe.c sed -e 's/^X//' >README <<'------ EOF ------' XThe recent Usenet worm demonstrated yet again that using gets() is asking Xfor trouble. However, gets() is often much more convenient than fgets(). XIt would be pleasant to combine the convenience of gets() with the safety Xof fgets(). getsafe() -- reading from stdin -- and fgetsafe -- reading Xfrom a stream passed as an argument -- are such combinations. X XJust compile with X cc -c getsafe.c Xand use. No warrentees, no promises, no copyrights. ------ EOF ------ ls -l README sed -e 's/^X//' >getsafe.c <<'------ EOF ------' X/* File : getsafe.c X Author : Richard A. O'Keefe @ Quintus Computer Systems, Inc. X Updated: 11 November 1988 X X Defines: getsafe() and fgetsafe() -- safe replacements for gets() X X This file is not covered by a copyright. Do what you like with it. X*/ X X#include X X#if 0 X X int getsafe(char *buffer, int length) X int fgetsafe(char *buffer, int length, FILE *stream) X X The functions read characters (getsafe reads from the standard input X stream, fgetsafe from its stream argument) until a new-line character X is read or the end of the stream is reached. Characters are stored X in buffer until length-1 of them have been stored, and a NUL is put X after the stored characters. The terminating new-line character is X not stored in the buffer. If the input line has more than length-1 X characters preceding the new-line, the excess characters are lost. X X If a new-line character is encountered, the return value is the X number of characters which were read, including the new-line. This X result also includes characters which were not stored, so you can X tell whether the line was truncated by doing X X n = getsafe(buffer, sizeof buffer); X if (n > sizeof buffer) { the line was truncated } X X If a new-line character is not encountered, characters will have been X read until the end of the stream was reached, and the return value is X 0 to indicate end of stream. This means that a last "line" which is X not terminated by a new-line will be lost. X X Loops which used to read X char buffer[ITSIZE]; X while (gets(buffer)) { process line } X can be converted to X while (getsafe(buffer, sizeof buffer)) { process line } X X#endif 0 X Xint fgetsafe(buffer, length, stream) X register char *buffer; X int length; X register FILE *stream; X { X register int c; X register int n; X X for (n = 0;;) { X c = getc(stream); X if (c == EOF ) { *buffer = '\0'; return 0; } X if (c == '\n') { *buffer = '\0'; return n; } X n++; X if (n < length) *buffer++ = c; X } X } X X Xint getsafe(buffer, length) X char *buffer; X int length; X { X return fgetsafe(buffer, length, stdin); X } X X X#ifdef TEST X X/* To test this, I did X cc -O -DTEST getsafe.c X cat /usr/dict/words | paste - - - - - - - - - - | a.out X*/ X Xmain() X { X char buffer[81]; X int n; X X while (n = getsafe(buffer, sizeof buffer)) X printf("%7d %7d\n", n, strlen(buffer)); X exit(0); X } X X#endif TEST X ------ EOF ------ ls -l getsafe.c exit 0