Commit cb7bc0d85ea9ec5eb8e9c922c2ad0ea7498620e9

Guillem Jover 2012-11-25T22:09:43

Add file buffer pool support to fgetln() This avoids buffer overwrites during concurrent or intermixed calls to fgetln() when using more than one different stream (currently 32), which the original interface supports natively by using an internal buffer from the FILE structure. Although this workaround is rudimentary, it should cover most of the theoretically problematic cases.

diff --git a/COPYING b/COPYING
index b84fb6f..5a42e50 100644
--- a/COPYING
+++ b/COPYING
@@ -66,7 +66,7 @@ for man/arc4random.3, man/tree.3 and man/getprogname.3.
 The rest of the licenses apply to code and/or man pages.
 
 
-    Copyright © 2004-2006, 2008-2011 Guillem Jover <guillem@hadrons.org>
+    Copyright © 2004-2006, 2008-2012 Guillem Jover <guillem@hadrons.org>
     Copyright © 2005 Hector Garcia Alvarez
     Copyright © 2005 Aurelien Jarno
     Copyright © 2006 Robert Millan
diff --git a/src/fgetln.c b/src/fgetln.c
index 183e853..6de804b 100644
--- a/src/fgetln.c
+++ b/src/fgetln.c
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2005 Hector Garcia Alvarez
- * Copyright © 2005, 2008, 2009, 2011 Guillem Jover <guillem@hadrons.org>
+ * Copyright © 2005, 2008-2012 Guillem Jover <guillem@hadrons.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,21 +31,41 @@
 #include <string.h>
 
 #ifdef HAVE_GETLINE
+struct filebuf {
+	FILE *fp;
+	char *buf;
+	size_t len;
+};
+
+#define FILEBUF_POOL_ITEMS 32
+
+static struct filebuf fb_pool[FILEBUF_POOL_ITEMS];
+static int fb_pool_cur;
+
 char *
 fgetln(FILE *stream, size_t *len)
 {
-	static char *line = NULL;
-	static size_t line_len = 0;
+	struct filebuf *fb;
 	ssize_t nread;
 
-	nread = getline(&line, &line_len, stream);
+	/* Try to diminish the possibility of several fgetln() calls being
+	 * used on different streams, by using a pool of buffers per file. */
+	fb = &fb_pool[fb_pool_cur];
+	if (fb->fp != stream && fb->fp != NULL) {
+		fb_pool_cur++;
+		fb_pool_cur %= FILEBUF_POOL_ITEMS;
+		fb = &fb_pool[fb_pool_cur];
+	}
+	fb->fp = stream;
+
+	nread = getline(&fb->buf, &fb->len, stream);
 	/* Note: the getdelim/getline API ensures nread != 0. */
 	if (nread == -1) {
 		*len = 0;
 		return NULL;
 	} else {
 		*len = (size_t)nread;
-		return line;
+		return fb->buf;
 	}
 }
 #else