Attachment "tcl8.5b3-state-limit.patch" to
ticket [1810264fff]
added by
gwad
2007-12-18 03:17:06.
diff -prauN tcl8.5b3.orig/generic/regc_nfa.c tcl8.5b3/generic/regc_nfa.c
--- tcl8.5b3.orig/generic/regc_nfa.c 2007-11-15 13:38:50.000000000 -0800
+++ tcl8.5b3/generic/regc_nfa.c 2007-12-17 11:35:55.000000000 -0800
@@ -58,11 +58,12 @@ newnfa(
nfa->nstates = 0;
nfa->cm = cm;
nfa->v = v;
+ nfa->size = 0;
nfa->bos[0] = nfa->bos[1] = COLORLESS;
nfa->eos[0] = nfa->eos[1] = COLORLESS;
+ nfa->parent = parent; /* must be before newfstate to ensure parent is valid */
nfa->post = newfstate(nfa, '@'); /* number 0 */
nfa->pre = newfstate(nfa, '>'); /* number 1 */
- nfa->parent = parent;
nfa->init = newstate(nfa); /* may become invalid later */
nfa->final = newstate(nfa);
@@ -85,6 +86,57 @@ newnfa(
}
/*
+ - too_many_states - checks if the max states exceeds the compile-time value
+ ^ static int too_many_states(struct nfa *);
+ */
+static int
+too_many_states(
+ struct nfa *nfa)
+{
+ struct nfa *parent = nfa->parent;
+ size_t sz = nfa->size;
+ while (parent != NULL) {
+ sz = parent->size;
+ parent = parent->parent;
+ }
+ if (sz > REG_MAX_STATES)
+ return 1;
+ return 0;
+}
+
+/*
+ - increment_size - increases the tracked size of the NFA and its parents.
+ ^ static void increment_size(struct nfa *);
+ */
+static void
+increment_size(
+ struct nfa *nfa)
+{
+ struct nfa *parent = nfa->parent;
+ nfa->size++;
+ while (parent != NULL) {
+ parent->size++;
+ parent = parent->parent;
+ }
+}
+
+/*
+ - decrement_size - increases the tracked size of the NFA and its parents.
+ ^ static void decrement_size(struct nfa *);
+ */
+static void
+decrement_size(
+ struct nfa *nfa)
+{
+ struct nfa *parent = nfa->parent;
+ nfa->size--;
+ while (parent != NULL) {
+ parent->size--;
+ parent = parent->parent;
+ }
+}
+
+/*
- freenfa - free an entire NFA
^ static VOID freenfa(struct nfa *);
*/
@@ -120,6 +172,11 @@ newstate(
{
struct state *s;
+ if (too_many_states(nfa)) {
+ /* XXX: add specific error for this */
+ NERR(REG_ETOOBIG);
+ return NULL;
+ }
if (nfa->free != NULL) {
s = nfa->free;
nfa->free = s->next;
@@ -152,6 +209,8 @@ newstate(
}
s->prev = nfa->slast;
nfa->slast = s;
+ /* Track the current size and the parent size */
+ increment_size(nfa);
return s;
}
@@ -222,6 +281,7 @@ freestate(
s->prev = NULL;
s->next = nfa->free; /* don't delete it, put it on the free list */
nfa->free = s;
+ decrement_size(nfa);
}
/*
diff -prauN tcl8.5b3.orig/generic/regerrs.h tcl8.5b3/generic/regerrs.h
--- tcl8.5b3.orig/generic/regerrs.h 1999-10-12 19:22:17.000000000 -0700
+++ tcl8.5b3/generic/regerrs.h 2007-12-17 11:35:40.000000000 -0800
@@ -16,3 +16,4 @@
{ REG_INVARG, "REG_INVARG", "invalid argument to regex function" },
{ REG_MIXED, "REG_MIXED", "character widths of regex and string differ" },
{ REG_BADOPT, "REG_BADOPT", "invalid embedded option" },
+{ REG_ETOOBIG, "REG_ETOOBIG", "nfa has too many states" },
diff -prauN tcl8.5b3.orig/generic/regex.h tcl8.5b3/generic/regex.h
--- tcl8.5b3.orig/generic/regex.h 2005-11-26 18:33:48.000000000 -0800
+++ tcl8.5b3/generic/regex.h 2007-12-17 11:35:54.000000000 -0800
@@ -277,6 +277,7 @@ typedef struct {
#define REG_INVARG 16 /* invalid argument to regex function */
#define REG_MIXED 17 /* character widths of regex and string differ */
#define REG_BADOPT 18 /* invalid embedded option */
+#define REG_ETOOBIG 19 /* nfa has too many states */
/* two specials for debugging and testing */
#define REG_ATOI 101 /* convert error-code name to number */
#define REG_ITOA 102 /* convert error-code number to name */
diff -prauN tcl8.5b3.orig/generic/regguts.h tcl8.5b3/generic/regguts.h
--- tcl8.5b3.orig/generic/regguts.h 2007-11-14 03:04:59.000000000 -0800
+++ tcl8.5b3/generic/regguts.h 2007-12-17 11:26:03.000000000 -0800
@@ -303,6 +303,7 @@ struct nfa {
struct colormap *cm; /* the color map */
color bos[2]; /* colors, if any, assigned to BOS and BOL */
color eos[2]; /* colors, if any, assigned to EOS and EOL */
+ size_t size; /* current NFA size; differs from nstates as it will be incremented by its children. */
struct vars *v; /* simplifies compile error reporting */
struct nfa *parent; /* parent NFA, if any */
};
@@ -331,6 +332,12 @@ struct cnfa {
#define ZAPCNFA(cnfa) ((cnfa).nstates = 0)
#define NULLCNFA(cnfa) ((cnfa).nstates == 0)
+/* Used to limit the maximum NFA size */
+#ifndef REG_MAX_STATES
+# define REG_MAX_STATES 100000
+#endif
+
+
/*
* subexpression tree
*/