summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2014-03-25 14:58:00 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2014-03-25 14:58:00 +0100
commit0c3d9dacafdb807d2101c67610969707353f434a (patch)
tree4abd0f7a4178332150791bda73c5f3185a403dc7
parent4e7c974d22ee5d938d8d8e7018f0a63f609d630b (diff)
Fixes file descriptor leak when parser ends with error.
Thanks to MrBr for the bugreport.
-rw-r--r--conf/cf-lex.l33
-rw-r--r--conf/conf.c1
-rw-r--r--conf/conf.h2
3 files changed, 31 insertions, 5 deletions
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index b1bbeae2..99785057 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -275,9 +275,6 @@ cf_hash(byte *c)
* match - these do not have fd and flex buffer yet).
*
* FIXME: Most of these ifs and include functions are really sysdep/unix.
- *
- * FIXME: Resources (fd, flex buffers and glob data) in IFS stack
- * are not freed when cf_error() is called.
*/
static struct include_file_stack *
@@ -316,13 +313,36 @@ enter_ifs(struct include_file_stack *new)
yy_switch_to_buffer(new->buffer);
}
+/**
+ * cf_lex_unwind - unwind lexer state during error
+ *
+ * cf_lex_unwind() frees the internal state on IFS stack when the lexical
+ * analyzer is terminated by cf_error().
+ */
+void
+cf_lex_unwind(void)
+{
+ struct include_file_stack *n;
+
+ for (n = ifs; n != ifs_head; n = n->prev)
+ {
+ /* Memory is freed automatically */
+ if (n->buffer)
+ yy_delete_buffer(n->buffer);
+ if (n->fd)
+ close(n->fd);
+ }
+
+ ifs = ifs_head;
+}
+
static void
cf_include(char *arg, int alen)
{
struct include_file_stack *base_ifs = ifs;
int new_depth, rv, i;
char *patt;
- glob_t g;
+ glob_t g = {};
new_depth = ifs->depth + 1;
if (new_depth > MAX_INCLUDE_DEPTH)
@@ -370,7 +390,10 @@ cf_include(char *arg, int alen)
struct stat fs;
if (stat(fname, &fs) < 0)
- cf_error("Unable to stat included file %s: %m", fname);
+ {
+ globfree(&g);
+ cf_error("Unable to stat included file %s: %m", fname);
+ }
if (fs.st_mode & S_IFDIR)
continue;
diff --git a/conf/conf.c b/conf/conf.c
index 67b027ce..a907402d 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -502,6 +502,7 @@ cf_error(char *msg, ...)
new_config->err_msg = cfg_strdup(buf);
new_config->err_lino = ifs->lino;
new_config->err_file_name = ifs->file_name;
+ cf_lex_unwind();
longjmp(conf_jmpbuf, 1);
}
diff --git a/conf/conf.h b/conf/conf.h
index a8bba7e8..fa14d7b5 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -139,6 +139,8 @@ extern struct include_file_stack *ifs;
int cf_lex(void);
void cf_lex_init(int is_cli, struct config *c);
+void cf_lex_unwind(void);
+
struct symbol *cf_find_symbol(byte *c);
struct symbol *cf_default_name(char *template, int *counter);
struct symbol *cf_define_symbol(struct symbol *symbol, int type, void *def);