Module Name:    src
Committed By:   dholland
Date:           Sun Mar 11 07:27:03 UTC 2012

Modified Files:
        src/usr.bin/config: gram.y

Log Message:
Strengthen the logic that wraps allocations going on the parser stack.
(This allows cleaning up when a syntax error occurs, because yacc just
dumps the parser stack on the floor.)

The new logic can handle arbitrary data types instead of being limited
to struct nvlist.


To generate a diff of this commit:
cvs rdiff -u -r1.30 -r1.31 src/usr.bin/config/gram.y

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/config/gram.y
diff -u src/usr.bin/config/gram.y:1.30 src/usr.bin/config/gram.y:1.31
--- src/usr.bin/config/gram.y:1.30	Sun Mar 11 02:56:25 2012
+++ src/usr.bin/config/gram.y	Sun Mar 11 07:27:02 2012
@@ -1,5 +1,5 @@
 %{
-/*	$NetBSD: gram.y,v 1.30 2012/03/11 02:56:25 dholland Exp $	*/
+/*	$NetBSD: gram.y,v 1.31 2012/03/11 07:27:02 dholland Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -58,10 +58,31 @@
 
 static	struct	config conf;	/* at most one active at a time */
 
-/* the following is used to recover nvlist space after errors */
-static	struct	nvlist *alloc[1000];
-static	int	adepth;
-#define	new0(n,s,p,i,x)	(alloc[adepth++] = newnv(n, s, p, i, x))
+
+/*
+ * Allocation wrapper functions
+ */
+static void wrap_alloc(void *ptr, unsigned code);
+static void wrap_continue(void);
+static void wrap_cleanup(void);
+
+/*
+ * Allocation wrapper type codes
+ */
+#define WRAP_CODE_nvlist	1
+
+/*
+ * The allocation wrappers themselves
+ */
+#define DECL_ALLOCWRAP(t)	static struct t *wrap_mk_##t(struct t *arg)
+
+DECL_ALLOCWRAP(nvlist);
+
+/*
+ * Macros for allocating new objects
+ */
+
+#define	new0(n,s,p,i,x)	wrap_mk_nvlist(newnv(n, s, p, i, x))
 #define	new_n(n)	new0(n, NULL, NULL, 0, NULL)
 #define	new_nx(n, x)	new0(n, NULL, NULL, 0, x)
 #define	new_ns(n, s)	new0(n, s, NULL, 0, NULL)
@@ -80,7 +101,10 @@ static	int	adepth;
 #define	fx_and(e1, e2)	new0(NULL, NULL, e1, FX_AND, e2)
 #define	fx_or(e1, e2)	new0(NULL, NULL, e1, FX_OR, e2)
 
-static	void	cleanup(void);
+/*
+ * Other private functions
+ */
+
 static	void	setmachine(const char *, const char *, struct nvlist *, int);
 static	void	check_maxpart(void);
 
@@ -238,8 +262,8 @@ definition_part:
 definitions:
 	  /* empty */
 	| definitions '\n'
-	| definitions definition '\n'	{ adepth = 0; }
-	| definitions error '\n'	{ cleanup(); }
+	| definitions definition '\n'	{ wrap_continue(); }
+	| definitions error '\n'	{ wrap_cleanup(); }
 	| definitions ENDFILE		{ enddefs(); checkfiles(); }
 ;
 
@@ -557,8 +581,8 @@ configuration_part:
 config_items:
 	  /* empty */
 	| config_items '\n'
-	| config_items config_item '\n'	{ adepth = 0; }
-	| config_items error '\n'	{ cleanup(); }
+	| config_items config_item '\n'	{ wrap_continue(); }
+	| config_items error '\n'	{ wrap_cleanup(); }
 ;
 
 /* One config item. */
@@ -855,21 +879,89 @@ yyerror(const char *s)
 	cfgerror("%s", s);
 }
 
+/************************************************************/
+
+/*
+ * Wrap allocations that live on the parser stack so that we can free
+ * them again on error instead of leaking.
+ */
+
+#define MAX_WRAP 1000
+
+struct wrap_entry {
+	void *ptr;
+	unsigned typecode;
+};
+
+static struct wrap_entry wrapstack[MAX_WRAP];
+static unsigned wrap_depth;
+
 /*
- * Cleanup procedure after syntax error: release any nvlists
- * allocated during parsing the current line.
+ * Remember pointer PTR with type-code CODE.
  */
 static void
-cleanup(void)
+wrap_alloc(void *ptr, unsigned code)
 {
-	struct nvlist **np;
-	int i;
+	unsigned pos;
+
+	if (wrap_depth >= MAX_WRAP) {
+		panic("allocation wrapper stack overflow");
+	}
+	pos = wrap_depth++;
+	wrapstack[pos].ptr = ptr;
+	wrapstack[pos].typecode = code;
+}
+
+/*
+ * We succeeded; commit to keeping everything that's been allocated so
+ * far and clear the stack.
+ */
+static void
+wrap_continue(void)
+{
+	wrap_depth = 0;
+}
+
+/*
+ * We failed; destroy all the objects allocated.
+ */
+static void
+wrap_cleanup(void)
+{
+	unsigned i;
 
-	for (np = alloc, i = adepth; --i >= 0; np++)
-		nvfree(*np);
-	adepth = 0;
+	for (i=0; i<wrap_depth; i++) {
+		switch (wrapstack[i].typecode) {
+		    case WRAP_CODE_nvlist:
+			nvfree(wrapstack[i].ptr);
+			break;
+		    default:
+			panic("invalid code %u on allocation wrapper stack",
+			      wrapstack[i].typecode);
+		}
+	}
+	wrap_depth = 0;
 }
 
+/*
+ * Instantiate the wrapper functions.
+ *
+ * Each one calls wrap_alloc to save the pointer and then returns the
+ * pointer again; these need to be generated with the preprocessor in
+ * order to be typesafe.
+ */
+#define DEF_ALLOCWRAP(t) \
+	static struct t *				\
+	wrap_mk_##t(struct t *arg)			\
+	{						\
+		wrap_alloc(arg, WRAP_CODE_##t);		\
+		return arg;				\
+	}
+
+DEF_ALLOCWRAP(nvlist);
+
+/************************************************************/
+
 static void
 setmachine(const char *mch, const char *mcharch, struct nvlist *mchsubarches,
 	int isioconf)

Reply via email to