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
  */
