Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/config Strengthen the logic that wraps allocations g...



details:   https://anonhg.NetBSD.org/src/rev/7775d72a510a
branches:  trunk
changeset: 777971:7775d72a510a
user:      dholland <dholland%NetBSD.org@localhost>
date:      Sun Mar 11 07:27:02 2012 +0000

description:
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.

diffstat:

 usr.bin/config/gram.y |  128 ++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 110 insertions(+), 18 deletions(-)

diffs (178 lines):

diff -r 9593092428d2 -r 7775d72a510a usr.bin/config/gram.y
--- a/usr.bin/config/gram.y     Sun Mar 11 06:53:18 2012 +0000
+++ b/usr.bin/config/gram.y     Sun Mar 11 07:27:02 2012 +0000
@@ -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 @@
 #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 @@
 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 @@
 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 @@
        cfgerror("%s", s);
 }
 
+/************************************************************/
+
 /*
- * Cleanup procedure after syntax error: release any nvlists
- * allocated during parsing the current line.
+ * 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;
+
+/*
+ * Remember pointer PTR with type-code CODE.
+ */
+static void
+wrap_alloc(void *ptr, unsigned code)
+{
+       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
-cleanup(void)
+wrap_continue(void)
 {
-       struct nvlist **np;
-       int i;
+       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)



Home | Main Index | Thread Index | Old Index