[v2,3/4] Refactoring of indesc hierarchy.

Message ID 20180605143051.19274-4-david.fabian@bosson.cz
State RFC
Delegated to: Pablo Neira
Headers show
Series
  • Added support for per-file variable scopes and global variables
Related show

Commit Message

David Fabian June 5, 2018, 2:30 p.m.
Indesc structure is now bound to scopes. Fixed issues with glob includes
incorrectly increase the inclusion depth value. The entire scope tree gets 
cleaned up at the end of parsing now to properly support displaying of 
error messages.

---
 include/nftables.h |  10 +++--
 include/parser.h   |  15 +++----
 include/rule.h     |  15 +++++--
 src/parser_bison.y |  64 ++++++++++++++++++++--------
 src/rule.c         |  56 +++++++++++++++++++++----
 src/scanner.l      | 120 +++++++++++++++++++++--------------------------------
 6 files changed, 164 insertions(+), 116 deletions(-)

Patch

diff --git a/include/nftables.h b/include/nftables.h
index 5e209b4..28d6043 100644
--- a/include/nftables.h
+++ b/include/nftables.h
@@ -118,13 +118,15 @@  struct input_descriptor {
 	struct location			location;
 	enum input_descriptor_types	type;
 	const char			*name;
-	const char			*data;
+	union {
+		const char		*data;
+		FILE			*fp;
+	};
 	unsigned int			lineno;
 	unsigned int			column;
-	off_t				token_offset;
-	off_t				line_offset;
+	off_t					token_offset;
+	off_t					line_offset;
 };
-
 void ct_label_table_init(void);
 void mark_table_init(void);
 void gmp_init(void);
diff --git a/include/parser.h b/include/parser.h
index 1f3eb5f..eabb2f4 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -4,26 +4,19 @@ 
 #include <list.h>
 #include <rule.h> // FIXME
 
-#define MAX_INCLUDE_DEPTH		64
+#define MAX_INCLUDE_DEPTH		16
 #define TABSIZE				8
 
 #define YYLTYPE				struct location
 #define YYLTYPE_IS_TRIVIAL		0
 #define YYENABLE_NLS			0
 
-#define SCOPE_NEST_MAX			(MAX_INCLUDE_DEPTH + 3)
-
 struct parser_state {
-	struct input_descriptor		*indesc;
-	struct input_descriptor		indescs[MAX_INCLUDE_DEPTH];
-	unsigned int			indesc_idx;
-
 	struct list_head		*msgs;
 	unsigned int			nerrs;
 
-	struct scope			top_scope;
-	struct scope			*scopes[SCOPE_NEST_MAX];
-	unsigned int			scope;
+	struct scope 			*top_scope; // top-level scope
+	struct scope			*scope; // current scope
 
 	struct list_head		*cmds;
 	struct eval_ctx			ectx;
@@ -37,7 +30,9 @@  extern void parser_destroy(struct parser_state *state);
 
 extern void open_scope(struct parser_state *state, struct scope *scope);
 extern void close_scope(struct parser_state *state);
+extern struct scope *toplevel_scope(const struct parser_state *state);
 extern struct scope *current_scope(const struct parser_state *state);
+extern struct input_descriptor* get_indesc(struct parser_state *state);
 
 extern int nft_parse(struct nft_ctx *ctx, void *, struct parser_state *state);
 
diff --git a/include/rule.h b/include/rule.h
index 8991025..c2ff692 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -82,12 +82,19 @@  extern void handle_free(struct handle *h);
  * @parent:	pointer to parent scope
  * @symbols:	symbols bound in the scope
  */
+struct input_descriptor;
 struct scope {
-	const struct scope	*parent;
+	struct list_head	list;
+	struct scope	*parent;
+	struct list_head		scopes;
+	struct input_descriptor	*indesc;
+	int depth;
 	struct list_head	symbols;
 };
 
-extern struct scope *scope_init(struct scope *scope, const struct scope *parent);
+extern struct input_descriptor* indesc_alloc(void);
+extern struct scope *scope_alloc(struct scope *parent, 
+								 struct input_descriptor *parent_indesc);
 extern void scope_release(const struct scope *scope);
 
 /**
@@ -137,7 +144,7 @@  struct table {
 	struct list_head	list;
 	struct handle		handle;
 	struct location		location;
-	struct scope		scope;
+	struct scope		*scope;
 	struct list_head	chains;
 	struct list_head	sets;
 	struct list_head	objs;
@@ -190,7 +197,7 @@  struct chain {
 	int			policy;
 	const char		*type;
 	const char		*dev;
-	struct scope		scope;
+	struct scope		*scope;
 	struct list_head	rules;
 };
 
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 4500aac..9982c5b 100755
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -36,14 +36,23 @@ 
 
 #include "parser_bison.h"
 
+struct scope *toplevel_scope(const struct parser_state *state)
+{
+	return state->top_scope;
+}
+
+struct scope *current_scope(const struct parser_state *state)
+{
+	return state->scope;
+}
+
 void parser_init(struct nft_ctx *nft, struct parser_state *state,
 		 struct list_head *msgs, struct list_head *cmds)
 {
 	memset(state, 0, sizeof(*state));
-	init_list_head(&state->top_scope.symbols);
 	state->msgs = msgs;
 	state->cmds = cmds;
-	state->scopes[0] = scope_init(&state->top_scope, NULL);
+	state->top_scope = state->scope = scope_alloc(NULL, NULL);
 	state->ectx.cache = &nft->cache;
 	state->ectx.msgs = msgs;
 	state->ectx.nf_sock = nft->nf_sock;
@@ -53,7 +62,7 @@  void parser_init(struct nft_ctx *nft, struct parser_state *state,
 
 void parser_destroy(struct parser_state *state)
 {
-	scope_release(state->scopes[0]);
+	scope_release(state->top_scope);
 }
 
 static void yyerror(struct location *loc, struct nft_ctx *nft, void *scanner,
@@ -62,35 +71,50 @@  static void yyerror(struct location *loc, struct nft_ctx *nft, void *scanner,
 	erec_queue(error(loc, "%s", s), state->msgs);
 }
 
-static struct scope *toplevel_scope(const struct parser_state *state)
+void open_scope(struct parser_state *state, struct scope *scope)
 {
-	return state->scopes[0];
+	list_add_tail(&scope->list, &state->scope->scopes);
+	state->scope = scope;
 }
 
-struct scope *current_scope(const struct parser_state *state)
+void open_scope_glob(struct parser_state *state, struct scope *scope)
 {
-	return state->scopes[state->scope];
+	/* add the scope to the head of the current scope level list */
+	list_add(&scope->list, state->scope->list.prev);
+	state->scope = scope;
 }
 
-void open_scope(struct parser_state *state, struct scope *scope)
+void close_scope(struct parser_state *state)
 {
-	assert(state->scope < array_size(state->scopes) - 1);
-	scope_init(scope, current_scope(state));
-	state->scopes[++state->scope] = scope;
+	struct scope *scope = state->scope;
+	assert(state->scope->parent != NULL);
+
+	/* no additional globs, backtrack */
+	if (list_is_last(&scope->list, &scope->parent->scopes))
+		state->scope = scope->parent;
+	else
+		state->scope = list_entry(scope->list.next, struct scope, list);
 }
 
-void close_scope(struct parser_state *state)
+
+struct input_descriptor* get_indesc(struct parser_state *state)
 {
-	assert(state->scope > 0);
-	scope_release(state->scopes[state->scope]);
-	state->scope--;
+	struct scope *scope = state->scope;
+	while (scope) {
+		if (scope->indesc)
+			return scope->indesc;
+		scope = scope->parent;
+	}
+	/* should never happen */
+	assert(false);
+	return NULL;
 }
 
 static void location_init(void *scanner, struct parser_state *state,
 			  struct location *loc)
 {
 	memset(loc, 0, sizeof(*loc));
-	loc->indesc = state->indesc;
+	loc->indesc = get_indesc(state);
 }
 
 static void location_update(struct location *loc, struct location *rhs, int n)
@@ -1407,8 +1431,10 @@  describe_cmd		:	primary_expr
 
 table_block_alloc	:	/* empty */
 			{
+				struct scope *scope = scope_alloc(current_scope(state), NULL);
 				$$ = table_alloc();
-				open_scope(state, &$$->scope);
+				$$->scope->parent = current_scope(state);
+				open_scope(state, scope);
 			}
 			;
 
@@ -1518,8 +1544,10 @@  table_block		:	/* empty */	{ $$ = $<table>-1; }
 
 chain_block_alloc	:	/* empty */
 			{
+				struct scope *scope = scope_alloc(current_scope(state), NULL);
 				$$ = chain_alloc(NULL);
-				open_scope(state, &$$->scope);
+				$$->scope->parent = current_scope(state);
+				open_scope(state, scope);
 			}
 			;
 
diff --git a/src/rule.c b/src/rule.c
index d40ec50..aff6992 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -495,15 +495,42 @@  struct rule *rule_lookup(const struct chain *chain, uint64_t handle)
 	return NULL;
 }
 
-struct scope *scope_init(struct scope *scope, const struct scope *parent)
+struct input_descriptor* indesc_alloc(void)
 {
+	struct input_descriptor* indesc = xzalloc(sizeof(struct input_descriptor));
+	return indesc;
+}
+
+struct scope *scope_alloc(struct scope *parent, 
+						  struct input_descriptor *parent_indesc)
+{
+	struct scope *scope = xzalloc(sizeof(*scope));
+	init_list_head(&scope->list);
+	init_list_head(&scope->symbols);
+	init_list_head(&scope->scopes);
 	scope->parent = parent;
+	scope->indesc = parent_indesc;
+	if (parent != NULL)
+		scope->depth = parent->depth + 1;
 	return scope;
 }
 
-void scope_release(const struct scope *scope)
+static void scope_indesc_release(const struct input_descriptor *indesc)
+{
+	if (indesc == NULL)
+		return;
+	xfree(indesc->name);
+	if (indesc->type == INDESC_FILE) {
+		fclose(indesc->fp);
+	}
+}
+
+static void single_scope_release(const struct scope *scope)
 {
 	struct symbol *sym, *next;
+	
+	if (scope == NULL)
+		return;
 
 	list_for_each_entry_safe(sym, next, &scope->symbols, list) {
 		assert(sym->refcnt == 1);
@@ -512,6 +539,18 @@  void scope_release(const struct scope *scope)
 		expr_free(sym->expr);
 		xfree(sym);
 	}
+	scope_indesc_release(scope->indesc);
+	xfree(scope->indesc);
+}
+
+void scope_release(const struct scope *scope)
+{
+	struct scope *other_scope, *next;
+	list_for_each_entry_safe(other_scope, next, &scope->scopes, list) {
+		scope_release(other_scope);
+	}
+	single_scope_release(scope);
+	xfree(scope);
 }
 
 void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
@@ -635,10 +674,9 @@  struct chain *chain_alloc(const char *name)
 	chain = xzalloc(sizeof(*chain));
 	chain->refcnt = 1;
 	init_list_head(&chain->rules);
-	init_list_head(&chain->scope.symbols);
+	chain->scope = scope_alloc(NULL, NULL);
 	if (name != NULL)
-		chain->handle.chain.name = xstrdup(name);
-
+	chain->handle.chain.name = xstrdup(name);
 	chain->policy = -1;
 	return chain;
 }
@@ -658,7 +696,8 @@  void chain_free(struct chain *chain)
 	list_for_each_entry_safe(rule, next, &chain->rules, list)
 		rule_free(rule);
 	handle_free(&chain->handle);
-	scope_release(&chain->scope);
+	list_del(&chain->scope->list);
+	scope_release(chain->scope);
 	xfree(chain->type);
 	if (chain->dev != NULL)
 		xfree(chain->dev);
@@ -816,7 +855,7 @@  struct table *table_alloc(void)
 	init_list_head(&table->sets);
 	init_list_head(&table->objs);
 	init_list_head(&table->flowtables);
-	init_list_head(&table->scope.symbols);
+	table->scope = scope_alloc(NULL, NULL);
 	table->refcnt = 1;
 
 	return table;
@@ -837,7 +876,8 @@  void table_free(struct table *table)
 	list_for_each_entry_safe(obj, nobj, &table->objs, list)
 		obj_free(obj);
 	handle_free(&table->handle);
-	scope_release(&table->scope);
+	list_del(&table->scope->list);
+	scope_release(table->scope);
 	xfree(table);
 }
 
diff --git a/src/scanner.l b/src/scanner.l
index 96bb307..e190811 100755
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -56,41 +56,43 @@ 
 	}									\
 }
 
-static void scanner_pop_buffer(yyscan_t scanner);
-
-
 static void init_pos(struct parser_state *state)
 {
-	state->indesc->lineno		= 1;
-	state->indesc->column		= 1;
-	state->indesc->token_offset	= 0;
-	state->indesc->line_offset 	= 0;
+	struct input_descriptor *indesc = get_indesc(state);
+/* 	printf("initializing pos to %p, name %s\n", indesc, indesc->name); */
+	indesc->lineno		= 1;
+	indesc->column		= 1;
+	indesc->token_offset	= 0;
+	indesc->line_offset 	= 0;
 }
 
 static void update_pos(struct parser_state *state, struct location *loc,
 		       int len)
 {
-	loc->indesc			= state->indesc;
-	loc->first_line			= state->indesc->lineno;
-	loc->last_line			= state->indesc->lineno;
-	loc->first_column		= state->indesc->column;
-	loc->last_column		= state->indesc->column + len - 1;
-	state->indesc->column		+= len;
+	struct input_descriptor *indesc = get_indesc(state);
+	loc->indesc			= indesc;
+	loc->first_line			= indesc->lineno;
+	loc->last_line			= indesc->lineno;
+	loc->first_column		= indesc->column;
+	loc->last_column		= indesc->column + len - 1;
+	indesc->column			+= len;
 }
 
 static void update_offset(struct parser_state *state, struct location *loc,
 			  unsigned int len)
 {
-	state->indesc->token_offset	+= len;
-	loc->token_offset		= state->indesc->token_offset;
-	loc->line_offset		= state->indesc->line_offset;
+	struct input_descriptor *indesc = get_indesc(state);
+	indesc->token_offset	+= len;
+	loc->token_offset		= indesc->token_offset;
+	loc->line_offset		= indesc->line_offset;
 }
 
 static void reset_pos(struct parser_state *state, struct location *loc)
 {
-	state->indesc->line_offset	= state->indesc->token_offset;
-	state->indesc->lineno		+= 1;
-	state->indesc->column		= 1;
+	struct input_descriptor *indesc = get_indesc(state);
+	indesc->line_offset	= indesc->token_offset;
+	indesc->lineno		+= 1;
+	indesc->column		= 1;
 }
 
 #define YY_USER_ACTION {					\
@@ -620,7 +622,7 @@  addrstring	({macaddr}|{ip4addr}|{ip6addr})
 				unsigned int diff;
 
 				diff = TABSIZE - strlen("\t");
-				diff -= (state->indesc->column -
+				diff -= (get_indesc(state)->column -
 					 strlen("\t") - 1) % TABSIZE;
 
 				update_pos(state, yylloc, diff);
@@ -631,15 +633,9 @@  addrstring	({macaddr}|{ip4addr}|{ip6addr})
 
 <<EOF>> 		{
 				struct parser_state *state = yyget_extra(yyscanner);
-				struct scope *scope = current_scope(state);
 				update_pos(state, yylloc, 1);
-				/* only close scope if file was included, skip buffer parsing
-				   since it does not create new scope */
-				if (state->indesc && state->indesc->name) {
-					close_scope(state);
-					xfree(scope);
-				}
-				scanner_pop_buffer(yyscanner);
+				close_scope(state);
+				yypop_buffer_state(yyscanner);
 				if (YY_CURRENT_BUFFER == NULL)
 					return TOKEN_EOF;
 			}
@@ -648,26 +644,15 @@  addrstring	({macaddr}|{ip4addr}|{ip6addr})
 
 %%
 
-static void scanner_pop_buffer(yyscan_t scanner)
-{
-	struct parser_state *state = yyget_extra(scanner);
-
-	yypop_buffer_state(scanner);
-	if (state->indesc && state->indesc->name) {
-		xfree(state->indesc->name);
-		state->indesc->name = NULL;
-	}
-	state->indesc = &state->indescs[--state->indesc_idx - 1];
-}
-
 static struct error_record *scanner_push_file(void *scanner, const char *filename,
-					      FILE *f, const struct location *loc)
+					      FILE *f, const struct location *loc, struct scope *parent)
 {
 	struct parser_state *state = yyget_extra(scanner);
-	struct scope *scope = NULL;
+	struct scope *scope = scope_alloc(parent, indesc_alloc());
 	YY_BUFFER_STATE b;
 
-	if (state->indesc_idx == MAX_INCLUDE_DEPTH) {
+	if (scope->depth == MAX_INCLUDE_DEPTH) {
+		scope_release(scope);
 		fclose(f);
 		return error(loc, "Include nested too deeply, max %u levels",
 			     MAX_INCLUDE_DEPTH);
@@ -676,20 +661,21 @@  static struct error_record *scanner_push_file(void *scanner, const char *filenam
 	b = yy_create_buffer(f, YY_BUF_SIZE, scanner);
 	yypush_buffer_state(b, scanner);
 
-	state->indesc = &state->indescs[state->indesc_idx++];
 	if (loc != NULL)
-		state->indesc->location = *loc;
-	state->indesc->type	= INDESC_FILE;
-	state->indesc->name	= xstrdup(filename);
+		scope->indesc->location = *loc;
+	scope->indesc->type	= INDESC_FILE;
+	scope->indesc->name	= xstrdup(filename);
+	scope->indesc->fp	= f;
+	if (current_scope(state)->parent == parent)
+		open_scope_glob(state, scope);
+	else
+		open_scope(state, scope);
 	init_pos(state);
-	scope = xzalloc(sizeof(*scope));
-	init_list_head(&scope->symbols);
-	open_scope(state, scope);
 	return NULL;
 }
 
 static int include_file(void *scanner, const char *filename,
-			const struct location *loc)
+			const struct location *loc, struct scope *parent)
 {
 	struct parser_state *state = yyget_extra(scanner);
 	struct error_record *erec;
@@ -702,7 +688,7 @@  static int include_file(void *scanner, const char *filename,
 		goto err;
 	}
 
-	erec = scanner_push_file(scanner, filename, f, loc);
+	erec = scanner_push_file(scanner, filename, f, loc, parent);
 	if (erec != NULL)
 		goto err;
 	return 0;
@@ -716,6 +702,7 @@  static int include_glob(void *scanner, const char *pattern,
 {
 	struct parser_state *state = yyget_extra(scanner);
 	struct error_record *erec = NULL;
+	struct scope *scope = current_scope(state);
 	bool wildcard = false;
 	glob_t glob_data;
 	unsigned int i;
@@ -775,7 +762,7 @@  static int include_glob(void *scanner, const char *pattern,
 			if (len == 0 || path[len - 1] == '/')
 				continue;
 
-			ret = include_file(scanner, path, loc);
+			ret = include_file(scanner, path, loc, scope);
 			if (ret != 0)
 				goto err;
 		}
@@ -812,7 +799,8 @@  err:
 int scanner_read_file(void *scanner, const char *filename,
 		      const struct location *loc)
 {
-	return include_file(scanner, filename, loc);
+	struct parser_state *state = yyget_extra(scanner);
+	return include_file(scanner, filename, loc, current_scope(state));
 }
 
 static bool search_in_include_path(const char *filename)
@@ -878,12 +866,14 @@  void scanner_push_buffer(void *scanner, const struct input_descriptor *indesc,
 			 const char *buffer)
 {
 	struct parser_state *state = yyget_extra(scanner);
+	struct scope *scope = scope_alloc(current_scope(state), indesc_alloc());
 	YY_BUFFER_STATE b;
 
-	state->indesc = &state->indescs[state->indesc_idx++];
-	memcpy(state->indesc, indesc, sizeof(*state->indesc));
-	state->indesc->data = buffer;
-	state->indesc->name = NULL;
+	open_scope(state, scope);
+	scope->indesc->type = indesc->type;
+	scope->indesc->name = xstrdup(indesc->name);
+	scope->indesc->data = buffer;
+	scope->indesc->name = NULL;
 
 	b = yy_scan_string(buffer, scanner);
 	assert(b != NULL);
@@ -894,8 +884,6 @@  void *scanner_init(struct parser_state *state)
 {
 	yyscan_t scanner;
 
-	state->indesc = state->indescs;
-
 	yylex_init_extra(state, &scanner);
 	yyset_out(NULL, scanner);
 
@@ -904,17 +892,5 @@  void *scanner_init(struct parser_state *state)
 
 void scanner_destroy(void *scanner)
 {
-	struct parser_state *state = yyget_extra(scanner);
-
-	do {
-		struct input_descriptor *inpdesc =
-			&state->indescs[state->indesc_idx];
-		if (inpdesc && inpdesc->name) {
-			xfree(inpdesc->name);
-			inpdesc->name = NULL;
-		}
-		yypop_buffer_state(scanner);
-	} while (state->indesc_idx--);
-
 	yylex_destroy(scanner);
 }