summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorChad Loder <cloder@cvs.openbsd.org>2006-10-14 23:57:40 +0000
committerChad Loder <cloder@cvs.openbsd.org>2006-10-14 23:57:40 +0000
commitdba8c558535c38f881f7b7036ca133d4000f1970 (patch)
tree05314895fe837c190d785f4c28fd7f9a954ba932 /lib/libc
parent8ad6a4c4e4afe7be8dc3c334a9b9abac22607f0d (diff)
Add a CAVEAT section that describes how to properly trim a newline from
a string, being careful to deal with 0-length strings. Help and input from jmc, ok deraadt
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/stdio/fgets.351
1 files changed, 41 insertions, 10 deletions
diff --git a/lib/libc/stdio/fgets.3 b/lib/libc/stdio/fgets.3
index 62f6fb8e7b4..65b72fe0b7e 100644
--- a/lib/libc/stdio/fgets.3
+++ b/lib/libc/stdio/fgets.3
@@ -1,4 +1,4 @@
-.\" $OpenBSD: fgets.3,v 1.22 2006/10/14 18:50:32 cloder Exp $
+.\" $OpenBSD: fgets.3,v 1.23 2006/10/14 23:57:39 cloder Exp $
.\"
.\" Copyright (c) 1990, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -147,17 +147,17 @@ conform to
.Sh CAVEATS
The following bit of code illustrates a case where the programmer assumes a
string is too long if it does not contain a newline:
-.Bd -literal
- char buf[1024], *p;
+.Bd -literal -offset indent
+char buf[1024], *p;
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- if ((p = strchr(buf, '\en')) == NULL) {
- fprintf(stderr, "input line too long.\en");
- exit(1);
- }
- *p = '\e0';
- printf("%s\en", buf);
+while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if ((p = strchr(buf, '\en')) == NULL) {
+ fprintf(stderr, "input line too long.\en");
+ exit(1);
}
+ *p = '\e0';
+ printf("%s\en", buf);
+}
.Ed
.Pp
While the error would be true if a line > 1023 characters were read, it would
@@ -189,6 +189,37 @@ which may indeed include a newline.
Consider using
.Xr fgetln 3
instead when dealing with untrusted input.
+.Pp
+It is erroneous to assume that
+.Fn fgets
+never returns an empty string when successful.
+If a line starts with the NUL character, fgets will store the NUL and
+continue reading until it encounters a newline or end-of-file.
+This will result in an empty string being returned.
+The following bit of code illustrates a case where the programmer assumes
+the string cannot be zero length.
+.Bd -literal -offset indent
+char buf[1024];
+
+if (fgets(buf, sizeof(buf), fp) != NULL) {
+ /* WRONG */
+ if (buf[strlen(buf) - 1] == '\en')
+ buf[strlen(buf) - 1] = '\e0';
+}
+.Ed
+.Pp
+If
+.Fn strlen
+returns 0, the index into the buffer becomes \-1.
+The correct way to trim a newline is shown below.
+.Bd -literal -offset indent
+char buf[1024];
+
+if (fgets(buf, sizeof(buf), fp) != NULL) {
+ if (buf[0] != '\e0' && buf[strlen(buf) - 1] == '\en')
+ buf[strlen(buf) - 1] = '\e0';
+}
+.Ed
.Sh BUGS
Since it is usually impossible to ensure that the next input line
is less than some arbitrary length, and because overflowing the