Browse Source

avoid C stack overflow during parsing

Roberto Ierusalimschy 23 years ago
parent
commit
04b143ddf9
3 changed files with 22 additions and 4 deletions
  1. 2 1
      llex.h
  2. 7 1
      llimits.h
  3. 13 2
      lparser.c

+ 2 - 1
llex.h

@@ -1,5 +1,5 @@
 /*
-** $Id: llex.h,v 1.44 2002/09/03 11:57:38 roberto Exp roberto $
+** $Id: llex.h,v 1.45 2002/10/08 18:46:08 roberto Exp roberto $
 ** Lexical Analyzer
 ** See Copyright Notice in lua.h
 */
@@ -59,6 +59,7 @@ typedef struct LexState {
   ZIO *z;  /* input stream */
   Mbuffer *buff;  /* buffer for tokens */
   TString *source;  /* current source name */
+  int nestlevel;  /* level of nested non-terminals */
 } LexState;
 
 

+ 7 - 1
llimits.h

@@ -1,5 +1,5 @@
 /*
-** $Id: llimits.h,v 1.46 2002/10/08 18:46:08 roberto Exp roberto $
+** $Id: llimits.h,v 1.47 2002/10/22 17:18:28 roberto Exp roberto $
 ** Limits, basic types, and some other `installation-dependent' definitions
 ** See Copyright Notice in lua.h
 */
@@ -165,4 +165,10 @@ typedef unsigned long Instruction;
 #endif
 
 
+/* maximum number of syntactical nested non-terminals */
+#ifndef LUA_MAXPARSERLEVEL
+#define LUA_MAXPARSERLEVEL	200
+#endif
+
+
 #endif

+ 13 - 2
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 1.196 2002/10/16 20:40:58 roberto Exp roberto $
+** $Id: lparser.c,v 1.197 2002/11/22 13:59:04 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -26,6 +26,10 @@
 #define getlocvar(fs, i)	((fs)->f->locvars[(fs)->actvar[i]])
 
 
+#define enterlevel(ls)	if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \
+		luaX_syntaxerror(ls, "too many syntax levels");
+#define leavelevel(ls)	((ls)->nestlevel--)
+
 
 /*
 ** nodes for block list (list of active blocks)
@@ -356,6 +360,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) {
   struct LexState lexstate;
   struct FuncState funcstate;
   lexstate.buff = buff;
+  lexstate.nestlevel = 0;
   luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z)));
   open_func(&lexstate, &funcstate);
   next(&lexstate);  /* read first token */
@@ -364,6 +369,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) {
   close_func(&lexstate);
   lua_assert(funcstate.prev == NULL);
   lua_assert(funcstate.f->nupvalues == 0);
+  lua_assert(lexstate.nestlevel == 0);
   return funcstate.f;
 }
 
@@ -749,7 +755,9 @@ static const struct {
 */
 static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
   BinOpr op;
-  UnOpr uop = getunopr(ls->t.token);
+  UnOpr uop;
+  enterlevel(ls);
+  uop = getunopr(ls->t.token);
   if (uop != OPR_NOUNOPR) {
     next(ls);
     subexpr(ls, v, UNARY_PRIORITY);
@@ -768,6 +776,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
     luaK_posfix(ls->fs, op, v, &v2);
     op = nextop;
   }
+  leavelevel(ls);
   return op;  /* return first untreated operator */
 }
 
@@ -1299,11 +1308,13 @@ static void body (LexState *ls, expdesc *e, int needself, int line) {
 static void chunk (LexState *ls) {
   /* chunk -> { stat [`;'] } */
   int islast = 0;
+  enterlevel(ls);
   while (!islast && !block_follow(ls->t.token)) {
     islast = statement(ls);
     testnext(ls, ';');
     lua_assert(ls->fs->freereg >= ls->fs->nactvar);
     ls->fs->freereg = ls->fs->nactvar;  /* free registers */
   }
+  leavelevel(ls);
 }