diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-02-27 12:42:16 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-02-27 12:42:16 -0300 |
| commit | d97fe6ed31d4b274c88c996b0c06da597a455149 (patch) | |
| tree | a37297862273c9e44197026923bc4a4c3d1e16f9 | |
| parent | f53caf1f863f140de1c1af51906e658c9fb7d7d6 (diff) | |
| download | lpeg-d97fe6ed31d4b274c88c996b0c06da597a455149.tar.gz lpeg-d97fe6ed31d4b274c88c996b0c06da597a455149.tar.bz2 lpeg-d97fe6ed31d4b274c88c996b0c06da597a455149.zip | |
Fixed bug when resizing capture list
Fixed the bug reported in
http://lua-users.org/lists/lua-l/2018-11/msg00080.html
The field 's' of the open group of captures inside a run-time capture
was being reused by the open group of the results of the run-time
capture, even though that open-group entry was being removed from
the list and then added again.
| -rw-r--r-- | lpcap.c | 10 | ||||
| -rw-r--r-- | lpvm.c | 83 |
2 files changed, 51 insertions, 42 deletions
| @@ -271,15 +271,15 @@ int finddyncap (Capture *cap, Capture *last) { | |||
| 271 | 271 | ||
| 272 | 272 | ||
| 273 | /* | 273 | /* |
| 274 | ** Calls a runtime capture. Returns number of captures removed by | 274 | ** Calls a runtime capture. Returns number of captures "removed" by the |
| 275 | ** the call, including the initial Cgroup. (Captures to be added are | 275 | ** call, that is, those inside the group capture. Captures to be added |
| 276 | ** on the Lua stack.) | 276 | ** are on the Lua stack. |
| 277 | */ | 277 | */ |
| 278 | int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) { | 278 | int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) { |
| 279 | int n, id; | 279 | int n, id; |
| 280 | lua_State *L = cs->L; | 280 | lua_State *L = cs->L; |
| 281 | int otop = lua_gettop(L); | 281 | int otop = lua_gettop(L); |
| 282 | Capture *open = findopen(close); | 282 | Capture *open = findopen(close); /* get open group capture */ |
| 283 | assert(captype(open) == Cgroup); | 283 | assert(captype(open) == Cgroup); |
| 284 | id = finddyncap(open, close); /* get first dynamic capture argument */ | 284 | id = finddyncap(open, close); /* get first dynamic capture argument */ |
| 285 | close->kind = Cclose; /* closes the group */ | 285 | close->kind = Cclose; /* closes the group */ |
| @@ -299,7 +299,7 @@ int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) { | |||
| 299 | } | 299 | } |
| 300 | else | 300 | else |
| 301 | *rem = 0; /* no dynamic captures removed */ | 301 | *rem = 0; /* no dynamic captures removed */ |
| 302 | return close - open; /* number of captures of all kinds removed */ | 302 | return close - open - 1; /* number of captures to be removed */ |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | 305 | ||
| @@ -45,18 +45,29 @@ typedef struct Stack { | |||
| 45 | 45 | ||
| 46 | 46 | ||
| 47 | /* | 47 | /* |
| 48 | ** Make the size of the array of captures 'cap' twice as large as needed | 48 | ** Ensures the size of array 'capture' (with size '*capsize' and |
| 49 | ** (which is 'captop'). ('n' is the number of new elements.) | 49 | ** 'captop' elements being used) is enough to accomodate 'n' extra |
| 50 | ** elements plus one. (Because several opcodes add stuff to the capture | ||
| 51 | ** array, it is simpler to ensure the array always has at least one free | ||
| 52 | ** slot upfront and check its size later.) | ||
| 50 | */ | 53 | */ |
| 51 | static Capture *doublecap (lua_State *L, Capture *cap, int captop, | 54 | static Capture *growcap (lua_State *L, Capture *capture, int *capsize, |
| 52 | int n, int ptop) { | 55 | int captop, int n, int ptop) { |
| 53 | Capture *newc; | 56 | if (*capsize - captop > n) |
| 54 | if (captop >= INT_MAX/((int)sizeof(Capture) * 2)) | 57 | return capture; /* no need to grow array */ |
| 55 | luaL_error(L, "too many captures"); | 58 | else { /* must grow */ |
| 56 | newc = (Capture *)lua_newuserdata(L, captop * 2 * sizeof(Capture)); | 59 | Capture *newc; |
| 57 | memcpy(newc, cap, (captop - n) * sizeof(Capture)); | 60 | int newsize = captop + n + 1; /* minimum size needed */ |
| 58 | lua_replace(L, caplistidx(ptop)); | 61 | if (newsize < INT_MAX/((int)sizeof(Capture) * 2)) |
| 59 | return newc; | 62 | newsize *= 2; /* twice that size, if not too big */ |
| 63 | else if (newsize >= INT_MAX/((int)sizeof(Capture))) | ||
| 64 | luaL_error(L, "too many captures"); | ||
| 65 | newc = (Capture *)lua_newuserdata(L, newsize * sizeof(Capture)); | ||
| 66 | memcpy(newc, capture, captop * sizeof(Capture)); | ||
| 67 | *capsize = newsize; | ||
| 68 | lua_replace(L, caplistidx(ptop)); | ||
| 69 | return newc; | ||
| 70 | } | ||
| 60 | } | 71 | } |
| 61 | 72 | ||
| 62 | 73 | ||
| @@ -109,24 +120,24 @@ static int resdyncaptures (lua_State *L, int fr, int curr, int limit) { | |||
| 109 | 120 | ||
| 110 | 121 | ||
| 111 | /* | 122 | /* |
| 112 | ** Add capture values returned by a dynamic capture to the capture list | 123 | ** Add capture values returned by a dynamic capture to the list |
| 113 | ** 'base', nested inside a group capture. 'fd' indexes the first capture | 124 | ** 'capture', nested inside a group. 'fd' indexes the first capture |
| 114 | ** value, 'n' is the number of values (at least 1). | 125 | ** value, 'n' is the number of values (at least 1). The open group |
| 126 | ** capture is already in 'capture', before the place for the new entries. | ||
| 115 | */ | 127 | */ |
| 116 | static void adddyncaptures (const char *s, Capture *base, int n, int fd) { | 128 | static void adddyncaptures (const char *s, Capture *capture, int n, int fd) { |
| 117 | int i; | 129 | int i; |
| 118 | base[0].kind = Cgroup; /* create group capture */ | 130 | assert(capture[-1].kind == Cgroup && capture[-1].siz == 0); |
| 119 | base[0].siz = 0; | 131 | capture[-1].idx = 0; /* make group capture an anonymous group */ |
| 120 | base[0].idx = 0; /* make it an anonymous group */ | 132 | for (i = 0; i < n; i++) { /* add runtime captures */ |
| 121 | for (i = 1; i <= n; i++) { /* add runtime captures */ | 133 | capture[i].kind = Cruntime; |
| 122 | base[i].kind = Cruntime; | 134 | capture[i].siz = 1; /* mark it as closed */ |
| 123 | base[i].siz = 1; /* mark it as closed */ | 135 | capture[i].idx = fd + i; /* stack index of capture value */ |
| 124 | base[i].idx = fd + i - 1; /* stack index of capture value */ | 136 | capture[i].s = s; |
| 125 | base[i].s = s; | ||
| 126 | } | 137 | } |
| 127 | base[i].kind = Cclose; /* close group */ | 138 | capture[n].kind = Cclose; /* close group */ |
| 128 | base[i].siz = 1; | 139 | capture[n].siz = 1; |
| 129 | base[i].s = s; | 140 | capture[n].s = s; |
| 130 | } | 141 | } |
| 131 | 142 | ||
| 132 | 143 | ||
| @@ -308,15 +319,15 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
| 308 | s = o + res; /* else update current position */ | 319 | s = o + res; /* else update current position */ |
| 309 | n = lua_gettop(L) - fr + 1; /* number of new captures */ | 320 | n = lua_gettop(L) - fr + 1; /* number of new captures */ |
| 310 | ndyncap += n; /* update number of dynamic captures */ | 321 | ndyncap += n; /* update number of dynamic captures */ |
| 311 | if (n > 0) { /* any new capture? */ | 322 | if (n == 0) /* no new captures? */ |
| 323 | captop--; /* remove open group */ | ||
| 324 | else { /* new captures; keep original open group */ | ||
| 312 | if (fr + n >= SHRT_MAX) | 325 | if (fr + n >= SHRT_MAX) |
| 313 | luaL_error(L, "too many results in match-time capture"); | 326 | luaL_error(L, "too many results in match-time capture"); |
| 314 | if ((captop += n + 2) >= capsize) { | 327 | /* add new captures + close group to 'capture' list */ |
| 315 | capture = doublecap(L, capture, captop, n + 2, ptop); | 328 | capture = growcap(L, capture, &capsize, captop, n + 1, ptop); |
| 316 | capsize = 2 * captop; | 329 | adddyncaptures(s, capture + captop, n, fr); |
| 317 | } | 330 | captop += n + 1; /* new captures + close group */ |
| 318 | /* add new captures to 'capture' list */ | ||
| 319 | adddyncaptures(s, capture + captop - n - 2, n, fr); | ||
| 320 | } | 331 | } |
| 321 | p++; | 332 | p++; |
| 322 | continue; | 333 | continue; |
| @@ -348,10 +359,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e, | |||
| 348 | pushcapture: { | 359 | pushcapture: { |
| 349 | capture[captop].idx = p->i.key; | 360 | capture[captop].idx = p->i.key; |
| 350 | capture[captop].kind = getkind(p); | 361 | capture[captop].kind = getkind(p); |
| 351 | if (++captop >= capsize) { | 362 | captop++; |
| 352 | capture = doublecap(L, capture, captop, 0, ptop); | 363 | capture = growcap(L, capture, &capsize, captop, 0, ptop); |
| 353 | capsize = 2 * captop; | ||
| 354 | } | ||
| 355 | p++; | 364 | p++; |
| 356 | continue; | 365 | continue; |
| 357 | } | 366 | } |
