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.
This commit is contained in:
Guillem Jover 2012-11-25 22:09:43 +01:00
parent 1be0bdb2c9
commit cb7bc0d85e
2 changed files with 26 additions and 6 deletions

View File

@ -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

View File

@ -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