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 /lpvm.c | |
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.
Diffstat (limited to 'lpvm.c')
-rw-r--r-- | lpvm.c | 83 |
1 files changed, 46 insertions, 37 deletions
@@ -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 | } |