|
@ -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 |
|
|
** Standard library for string operations and pattern-matching |
|
|
** See Copyright Notice in lua.h |
|
|
** See Copyright Notice in lua.h |
|
|
*/ |
|
|
*/ |
|
@ -26,7 +26,8 @@ |
|
|
|
|
|
|
|
|
/*
|
|
|
/*
|
|
|
** maximum number of captures that a pattern can do during |
|
|
** 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) |
|
|
#if !defined(LUA_MAXCAPTURES) |
|
|
#define LUA_MAXCAPTURES 32 |
|
|
#define LUA_MAXCAPTURES 32 |
|
@ -214,9 +215,10 @@ typedef struct MatchState { |
|
|
const char *src_end; /* end ('\0') of source string */ |
|
|
const char *src_end; /* end ('\0') of source string */ |
|
|
const char *p_end; /* end ('\0') of pattern */ |
|
|
const char *p_end; /* end ('\0') of pattern */ |
|
|
lua_State *L; |
|
|
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 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 { |
|
|
struct { |
|
|
const char *init; |
|
|
const char *init; |
|
|
ptrdiff_t len; |
|
|
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 |
|
|
** Maximum number of operators handled in a match before consulting |
|
|
** a match (to avoid non-linear complexity). The maximum will be: |
|
|
** 'string.pattlimit'. (This lower limit is only to avoid wasting time |
|
|
** (subject length) * A_REPS + B_REPS |
|
|
** consulting 'string.pattlimit' in simple matches.) |
|
|
*/ |
|
|
*/ |
|
|
#if !defined(A_REPS) |
|
|
#if !defined(PREPATTLIMIT) |
|
|
#define A_REPS 4 |
|
|
#define PREPATTLIMIT 200 |
|
|
#define B_REPS 100000 |
|
|
|
|
|
#endif |
|
|
#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) { |
|
|
static const char *match_capture (MatchState *ms, const char *s, int l) { |
|
|
size_t len; |
|
|
size_t len; |
|
|
l = check_capture(ms, l); |
|
|
l = check_capture(ms, l); |
|
@ -502,8 +524,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) { |
|
|
s = NULL; /* fail */ |
|
|
s = NULL; /* fail */ |
|
|
} |
|
|
} |
|
|
else { /* matched once */ |
|
|
else { /* matched once */ |
|
|
if (ms->nrep-- == 0) |
|
|
if (--ms->nrep == 0) |
|
|
luaL_error(ms->L, "pattern too complex"); |
|
|
checklimit(ms); |
|
|
switch (*ep) { /* handle optional suffix */ |
|
|
switch (*ep) { /* handle optional suffix */ |
|
|
case '?': { /* optional */ |
|
|
case '?': { /* optional */ |
|
|
const char *res; |
|
|
const char *res; |
|
@ -607,10 +629,8 @@ static void prepstate (MatchState *ms, lua_State *L, |
|
|
ms->src_init = s; |
|
|
ms->src_init = s; |
|
|
ms->src_end = s + ls; |
|
|
ms->src_end = s + ls; |
|
|
ms->p_end = p + lp; |
|
|
ms->p_end = p + lp; |
|
|
if (ls < (MAX_SIZET - B_REPS) / A_REPS) |
|
|
ms->nrep = PREPATTLIMIT; |
|
|
ms->nrep = A_REPS * ls + B_REPS; |
|
|
ms->usedlimit = 0; |
|
|
else /* overflow (very long subject) */ |
|
|
|
|
|
ms->nrep = MAX_SIZET; /* no limit */ |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|