|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
-** $Id: lstrlib.c,v 1.244 2016/04/07 15:40:07 roberto Exp roberto $
|
|
|
+** $Id: lstrlib.c,v 1.245 2016/04/08 21:15:02 roberto Exp roberto $
|
|
|
** Standard library for string operations and pattern-matching
|
|
|
** See Copyright Notice in lua.h
|
|
|
*/
|
|
@@ -26,7 +26,8 @@
|
|
|
|
|
|
/*
|
|
|
** maximum number of captures that a pattern can do during
|
|
|
-** pattern-matching. This limit is arbitrary.
|
|
|
+** pattern-matching. This limit is arbitrary, but must fit in
|
|
|
+** an unsigned char.
|
|
|
*/
|
|
|
#if !defined(LUA_MAXCAPTURES)
|
|
|
#define LUA_MAXCAPTURES 32
|
|
@@ -214,9 +215,10 @@ typedef struct MatchState {
|
|
|
const char *src_end; /* end ('\0') of source string */
|
|
|
const char *p_end; /* end ('\0') of pattern */
|
|
|
lua_State *L;
|
|
|
- size_t nrep; /* limit to avoid non-linear complexity */
|
|
|
+ lua_Unsigned nrep; /* limit to avoid non-linear complexity */
|
|
|
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
|
|
|
- int level; /* total number of captures (finished or unfinished) */
|
|
|
+ unsigned char level; /* total number of captures (finished or unfinished) */
|
|
|
+ unsigned char usedlimit; /* true if real limit for 'nrep' was used */
|
|
|
struct {
|
|
|
const char *init;
|
|
|
ptrdiff_t len;
|
|
@@ -235,13 +237,12 @@ static const char *match (MatchState *ms, const char *s, const char *p);
|
|
|
|
|
|
|
|
|
/*
|
|
|
-** parameters to control the maximum number of operators handled in
|
|
|
-** a match (to avoid non-linear complexity). The maximum will be:
|
|
|
-** (subject length) * A_REPS + B_REPS
|
|
|
+** Maximum number of operators handled in a match before consulting
|
|
|
+** 'string.pattlimit'. (This lower limit is only to avoid wasting time
|
|
|
+** consulting 'string.pattlimit' in simple matches.)
|
|
|
*/
|
|
|
-#if !defined(A_REPS)
|
|
|
-#define A_REPS 4
|
|
|
-#define B_REPS 100000
|
|
|
+#if !defined(PREPATTLIMIT)
|
|
|
+#define PREPATTLIMIT 200
|
|
|
#endif
|
|
|
|
|
|
|
|
@@ -421,6 +422,27 @@ static const char *end_capture (MatchState *ms, const char *s,
|
|
|
}
|
|
|
|
|
|
|
|
|
+static void checklimit (MatchState *ms) {
|
|
|
+ lua_State *L = ms->L;
|
|
|
+ lua_assert(ms->nrep == 0);
|
|
|
+ if (!ms->usedlimit) { /* have not used 'string.pattlimit' yet? */
|
|
|
+ int top = lua_gettop(L);
|
|
|
+ if (lua_getglobal(L, "string") == LUA_TTABLE &&
|
|
|
+ lua_getfield(L, -1, "pattlimit") != LUA_TNIL) { /* is it defined? */
|
|
|
+ lua_Unsigned limit = (lua_Unsigned)lua_tointeger(L, -1); /* get it */
|
|
|
+ if (limit > PREPATTLIMIT) /* discount cycles already used */
|
|
|
+ ms->nrep = limit - PREPATTLIMIT;
|
|
|
+ ms->usedlimit = 1; /* do not use 'pattlimit' again */
|
|
|
+ }
|
|
|
+ else /* no limit defined; set no limit */
|
|
|
+ ms->nrep = ~(lua_Unsigned)0;
|
|
|
+ lua_settop(L, top); /* pop 'string' table and (maybe) 'pattlimit' */
|
|
|
+ }
|
|
|
+ if (ms->nrep == 0)
|
|
|
+ luaL_error(L, "pattern too complex");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static const char *match_capture (MatchState *ms, const char *s, int l) {
|
|
|
size_t len;
|
|
|
l = check_capture(ms, l);
|
|
@@ -502,8 +524,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
|
|
|
s = NULL; /* fail */
|
|
|
}
|
|
|
else { /* matched once */
|
|
|
- if (ms->nrep-- == 0)
|
|
|
- luaL_error(ms->L, "pattern too complex");
|
|
|
+ if (--ms->nrep == 0)
|
|
|
+ checklimit(ms);
|
|
|
switch (*ep) { /* handle optional suffix */
|
|
|
case '?': { /* optional */
|
|
|
const char *res;
|
|
@@ -607,10 +629,8 @@ static void prepstate (MatchState *ms, lua_State *L,
|
|
|
ms->src_init = s;
|
|
|
ms->src_end = s + ls;
|
|
|
ms->p_end = p + lp;
|
|
|
- if (ls < (MAX_SIZET - B_REPS) / A_REPS)
|
|
|
- ms->nrep = A_REPS * ls + B_REPS;
|
|
|
- else /* overflow (very long subject) */
|
|
|
- ms->nrep = MAX_SIZET; /* no limit */
|
|
|
+ ms->nrep = PREPATTLIMIT;
|
|
|
+ ms->usedlimit = 0;
|
|
|
}
|
|
|
|
|
|
|