diff options
| -rw-r--r-- | bugs | 4052 |
1 files changed, 0 insertions, 4052 deletions
| @@ -1,4052 +0,0 @@ | |||
| 1 | --[=[ | ||
| 2 | ** lua.stx / llex.c | ||
| 3 | Tue Dec 2 10:45:48 EDT 1997 | ||
| 4 | >> BUG: "lastline" was not reset on function entry, so debug information | ||
| 5 | >> started only in the 2nd line of a function. | ||
| 6 | |||
| 7 | |||
| 8 | |||
| 9 | ================================================================= | ||
| 10 | --- Version 3.1 alpha | ||
| 11 | |||
| 12 | ** lua.c | ||
| 13 | Thu Jan 15 14:34:58 EDT 1998 | ||
| 14 | >> must include "stdlib.h" (for "exit()"). | ||
| 15 | |||
| 16 | ** lbuiltin.c / lobject.h | ||
| 17 | Thu Jan 15 14:34:58 EDT 1998 | ||
| 18 | >> MAX_WORD may be bigger than MAX_INT | ||
| 19 | (by lhf) | ||
| 20 | |||
| 21 | ** llex.c | ||
| 22 | Mon Jan 19 18:17:18 EDT 1998 | ||
| 23 | >> wrong line number (+1) in error report when file starts with "#..." | ||
| 24 | |||
| 25 | ** lstrlib.c | ||
| 26 | Tue Jan 27 15:27:49 EDT 1998 | ||
| 27 | >> formats like "%020d" were considered too big (3 digits); moreover, | ||
| 28 | >> some sistems limit printf to at most 500 chars, so we can limit sizes | ||
| 29 | >> to 2 digits (99). | ||
| 30 | |||
| 31 | ** lapi.c | ||
| 32 | Tue Jan 27 17:12:36 EDT 1998 | ||
| 33 | >> "lua_getstring" may create a new string, so should check GC | ||
| 34 | |||
| 35 | ** lstring.c / ltable.c | ||
| 36 | Wed Jan 28 14:48:12 EDT 1998 | ||
| 37 | >> tables can become full of "empty" slots, and keep growing without limits. | ||
| 38 | |||
| 39 | ** lstrlib.c | ||
| 40 | Mon Mar 9 15:26:09 EST 1998 | ||
| 41 | >> gsub('a', '(b?)%1*' ...) loops (because the capture is empty). | ||
| 42 | |||
| 43 | ** lstrlib.c | ||
| 44 | Mon May 18 19:20:00 EST 1998 | ||
| 45 | >> arguments for "format" 'x', 'X', 'o' and 'u' must be unsigned int. | ||
| 46 | |||
| 47 | |||
| 48 | |||
| 49 | ================================================================= | ||
| 50 | --- Version 3.1 | ||
| 51 | |||
| 52 | ** liolib.c / lauxlib.c | ||
| 53 | Mon Sep 7 15:57:02 EST 1998 | ||
| 54 | >> function "luaL_argerror" prints wrong argument number (from a user's point | ||
| 55 | of view) when functions have upvalues. | ||
| 56 | |||
| 57 | ** lstrlib.c | ||
| 58 | Tue Nov 10 17:29:36 EDT 1998 | ||
| 59 | >> gsub/strfind do not check whether captures are properly finished. | ||
| 60 | (by roberto/tomas) | ||
| 61 | |||
| 62 | ** lbuiltin.c | ||
| 63 | Fri Dec 18 11:22:55 EDT 1998 | ||
| 64 | >> "tonumber" goes crazy with negative numbers in other bases (not 10), | ||
| 65 | because "strtol" returns long, not unsigned long. | ||
| 66 | (by Visual C++) | ||
| 67 | |||
| 68 | ** lstrlib.c | ||
| 69 | Mon Jan 4 10:41:40 EDT 1999 | ||
| 70 | >> "format" does not check size of format item (such as "%00000...00000d"). | ||
| 71 | |||
| 72 | ** lapi.c | ||
| 73 | Wed Feb 3 14:40:21 EDT 1999 | ||
| 74 | >> getlocal cannot return the local itself, since lua_isstring and | ||
| 75 | lua_isnumber can modify it. | ||
| 76 | |||
| 77 | ** lstrlib.c | ||
| 78 | Thu Feb 4 17:08:50 EDT 1999 | ||
| 79 | >> format "%s" may break limit of "sprintf" on some machines. | ||
| 80 | (by Marcelo Sales) | ||
| 81 | |||
| 82 | ** lzio.c | ||
| 83 | Thu Mar 4 11:49:37 EST 1999 | ||
| 84 | >> file stream cannot call fread after EOF. | ||
| 85 | (by lhf) | ||
| 86 | |||
| 87 | |||
| 88 | |||
| 89 | ================================================================= | ||
| 90 | --- Version 3.2 (beta) | ||
| 91 | |||
| 92 | ** lstrlib.c | ||
| 93 | Fri Apr 30 11:10:20 EST 1999 | ||
| 94 | >> '$' at end of pattern was matching regular '$', too. | ||
| 95 | (by anna; since 2.5) | ||
| 96 | |||
| 97 | ** lbuiltin.c | ||
| 98 | Fri May 21 17:15:11 EST 1999 | ||
| 99 | >> foreach, foreachi, foreachvar points to function in stack when stack | ||
| 100 | can be reallocated. | ||
| 101 | (by tomas; since 3.2 beta) | ||
| 102 | |||
| 103 | ** lparser.c | ||
| 104 | Wed Jun 16 10:32:46 EST 1999 | ||
| 105 | >> cannot assign to unlimited variables, because it causes overflow in | ||
| 106 | the number of returns of a function. | ||
| 107 | (since 3.1) | ||
| 108 | |||
| 109 | |||
| 110 | |||
| 111 | ================================================================= | ||
| 112 | --- Version 3.2 | ||
| 113 | |||
| 114 | ** lmathlib.c | ||
| 115 | Wed Aug 18 11:28:38 EST 1999 | ||
| 116 | >> random(0) and random(x,0) are wrong (0 is read as no argument!). | ||
| 117 | (by Dave Bollinger; since 3.1) | ||
| 118 | |||
| 119 | ** lparser.c | ||
| 120 | Thu Sep 2 10:07:20 EST 1999 | ||
| 121 | >> in the (old) expression << ls->fs->f->consts[checkname(ls)] >>, checkname | ||
| 122 | could realloc f->consts. | ||
| 123 | (by Supratik Champati; since 3.2 beta) | ||
| 124 | |||
| 125 | ** lobject.c / lbuiltin.c | ||
| 126 | Wed Sep 8 17:41:54 EST 1999 | ||
| 127 | >> tonumber'e1' and tonumber(' ', x), for x!=10, gave 0 instead of nil. | ||
| 128 | (since 3.1) | ||
| 129 | |||
| 130 | ** lstrlib.c | ||
| 131 | Thu Nov 11 14:36:30 EDT 1999 | ||
| 132 | >> `strfind' does not handle \0 in plain search. | ||
| 133 | (by Jon Kleiser; since 3.1) | ||
| 134 | |||
| 135 | ** lparser.c | ||
| 136 | Wed Dec 29 16:05:43 EDT 1999 | ||
| 137 | >> return gives wrong line in debug information | ||
| 138 | (by lhf; since 3.2 [at least]) | ||
| 139 | |||
| 140 | ** ldo.c | ||
| 141 | Thu Dec 30 16:39:33 EDT 1999 | ||
| 142 | >> cannot reopen stdin (for binary mode) | ||
| 143 | (by lhf & roberto; since 3.1) | ||
| 144 | |||
| 145 | ** lapi.c | ||
| 146 | Thu Mar 2 09:41:53 EST 2000 | ||
| 147 | >> lua_settable should check stack space (it could call a T.M.) | ||
| 148 | (by lhf & celes; since 3.2; it was already fixed by fixed stack) | ||
| 149 | |||
| 150 | ** lparser.c | ||
| 151 | Mon Apr 3 09:59:06 EST 2000 | ||
| 152 | >> '%' should be in expfollow | ||
| 153 | (by Edgar Toernig; since 3.1; it was already fixed) | ||
| 154 | |||
| 155 | ** lbuiltin.c | ||
| 156 | Mon Apr 3 10:05:05 EST 2000 | ||
| 157 | >> tostring() without arguments gives seg. fault. | ||
| 158 | (by Edgar Toernig; since 3.0) | ||
| 159 | |||
| 160 | |||
| 161 | |||
| 162 | ================================================================= | ||
| 163 | --- Version 4.0 alpha | ||
| 164 | |||
| 165 | Tested with full test suites (as locked in Mon Apr 24 14:23:11 EST 2000) | ||
| 166 | in the following platforms: | ||
| 167 | * Linux - gcc, g++ | ||
| 168 | * AIX - gcc | ||
| 169 | * Solaris - gcc, cc | ||
| 170 | * IRIX - cc, cc-purify | ||
| 171 | * Windows - Visual C++ (.c e .cpp, warning level=4) | ||
| 172 | |||
| 173 | |||
| 174 | ** lstrlib.c | ||
| 175 | Tue May 2 15:27:58 EST 2000 | ||
| 176 | >> `strfind' gets wrong subject length when there is an offset | ||
| 177 | (by Jon Kleiser; since 4.0a) | ||
| 178 | |||
| 179 | ** lparser.c | ||
| 180 | Fri May 12 15:11:12 EST 2000 | ||
| 181 | >> first element in a list constructor is not adjusted to one value | ||
| 182 | >> (e.g. «a = {gsub('a','a','')}») | ||
| 183 | (by Tomas; since 4.0a) | ||
| 184 | |||
| 185 | ** lparser.c | ||
| 186 | Wed May 24 14:50:16 EST 2000 | ||
| 187 | >> record-constructor starting with an upvalue name gets an error | ||
| 188 | >> (e.g. «local a; function f() x = {a=1} end») | ||
| 189 | (by Edgar Toernig; since 3.1) | ||
| 190 | |||
| 191 | ** lparser.c | ||
| 192 | Tue Aug 29 15:56:05 EST 2000 | ||
| 193 | >> error message for `for' uses `while' | ||
| 194 | (since 4.0a; already corrected) | ||
| 195 | |||
| 196 | ** lgc.c | ||
| 197 | Tue Aug 29 15:57:41 EST 2000 | ||
| 198 | >> gc tag method for nil could call line hook | ||
| 199 | (by ry; since ?) | ||
| 200 | |||
| 201 | |||
| 202 | |||
| 203 | ================================================================= | ||
| 204 | --- Version 4.0 Beta | ||
| 205 | |||
| 206 | ** liolib.c | ||
| 207 | Fri Sep 22 15:12:37 EST 2000 | ||
| 208 | >> `read("*w")' should return nil at EOF | ||
| 209 | (by roberto; since 4.0b) | ||
| 210 | |||
| 211 | ** lvm.c | ||
| 212 | Mon Sep 25 11:47:48 EST 2000 | ||
| 213 | >> lua_gettable does not get key from stack top | ||
| 214 | (by Philip Yi; since 4.0b) | ||
| 215 | |||
| 216 | ** lgc.c | ||
| 217 | Mon Sep 25 11:50:48 EST 2000 | ||
| 218 | >> GC may crash when checking locked C closures | ||
| 219 | (by Philip Yi; since 4.0b) | ||
| 220 | |||
| 221 | ** lapi.c | ||
| 222 | Wed Sep 27 09:50:19 EST 2000 | ||
| 223 | >> lua_tag should return LUA_NOTAG for non-valid indices | ||
| 224 | (by Paul Hankin; since 4.0b) | ||
| 225 | |||
| 226 | ** llex.h / llex.c / lparser.c | ||
| 227 | Wed Sep 27 13:39:45 EST 2000 | ||
| 228 | >> parser overwrites semantic information when looking ahead | ||
| 229 | >> (e.g. «a = {print'foo'}») | ||
| 230 | (by Edgar Toernig; since 4.0b, deriving from previous bug) | ||
| 231 | |||
| 232 | ** liolib.c | ||
| 233 | Thu Oct 26 10:50:46 EDT 2000 | ||
| 234 | >> in function `read_file', realloc() doesn't free the buffer if it can't | ||
| 235 | >> allocate new memory | ||
| 236 | (by Mauro Vezzosi; since 4.0b) | ||
| 237 | |||
| 238 | |||
| 239 | |||
| 240 | ================================================================= | ||
| 241 | --- Version 4.0 | ||
| 242 | |||
| 243 | ** lparser.c | ||
| 244 | Wed Nov 29 09:51:44 EDT 2000 | ||
| 245 | >> parser does not accept a `;' after a `return' | ||
| 246 | (by lhf; since 4.0b) | ||
| 247 | |||
| 248 | ** liolib.c | ||
| 249 | Fri Dec 22 15:30:42 EDT 2000 | ||
| 250 | >> when `read' fails it must return nil (and not no value) | ||
| 251 | (by cassino; since at least 3.1) | ||
| 252 | |||
| 253 | ** lstring.c/lapi.c | ||
| 254 | Thu Feb 1 11:55:45 EDT 2001 | ||
| 255 | >> lua_pushuserdata(L, NULL) is buggy | ||
| 256 | (by Edgar Toernig; since 4.0) | ||
| 257 | |||
| 258 | ** ldo.c | ||
| 259 | Fri Feb 2 14:06:40 EDT 2001 | ||
| 260 | >> «while 1 dostring[[print('hello\n')]] end» never reclaims memory | ||
| 261 | (by Andrew Paton; since 4.0b) | ||
| 262 | |||
| 263 | ** lbaselib.c | ||
| 264 | Tue Feb 6 11:57:13 EDT 2001 | ||
| 265 | >> ESC (which starts precompiled code) in C is \33, not \27 | ||
| 266 | (by Edgar Toernig and lhf; since 4.0b) | ||
| 267 | |||
| 268 | ** lparser.c | ||
| 269 | Tue Jul 10 16:59:18 EST 2001 | ||
| 270 | >> error message for `%a' gave wrong line number | ||
| 271 | (by Leonardo Constantino; since 4.0) | ||
| 272 | |||
| 273 | ** lbaselib.c | ||
| 274 | Fri Dec 21 15:21:05 EDT 2001 | ||
| 275 | >> seg. fault when rawget/rawset get extra arguments | ||
| 276 | (by Eric Mauger; since 4.0b) | ||
| 277 | |||
| 278 | ** lvm.c | ||
| 279 | Wed Jun 19 13:28:20 EST 2002 | ||
| 280 | >> line hook gets wrong `ar' | ||
| 281 | (by Daniel C. Sinclair; since 4.0.b) | ||
| 282 | |||
| 283 | ** ldo.c | ||
| 284 | Wed Jun 19 13:31:49 EST 2002 | ||
| 285 | >> `protectedparser' may run GC, and then collect `filename' | ||
| 286 | >> (in function `parse_file') | ||
| 287 | (by Alex Bilyk; since 4.0) | ||
| 288 | |||
| 289 | |||
| 290 | |||
| 291 | |||
| 292 | ================================================================= | ||
| 293 | --- Version 5.0 alpha | ||
| 294 | |||
| 295 | ** lgc.c | ||
| 296 | Fri Aug 30 13:49:14 EST 2002 | ||
| 297 | >> GC metamethod stored in a weak metatable being collected together with | ||
| 298 | >> userdata may not be cleared properly | ||
| 299 | (by Roberto; since 5.0a) | ||
| 300 | |||
| 301 | ** lapi.c | ||
| 302 | Thu Nov 21 11:00:00 EST 2002 | ||
| 303 | >> ULONG_MAX>>10 may not fit into an int | ||
| 304 | (by Jeff Petkau; since 4.0) | ||
| 305 | |||
| 306 | ** lparser.c | ||
| 307 | Fri Dec 6 17:06:40 UTC 2002 | ||
| 308 | >> scope of generic for variables is not sound | ||
| 309 | (by Gavin Wraith; since 5.0a) | ||
| 310 | |||
| 311 | |||
| 312 | |||
| 313 | |||
| 314 | ================================================================= | ||
| 315 | --- Version 5.0 beta | ||
| 316 | ** lbaselib.c | ||
| 317 | Fri Dec 20 09:53:19 UTC 2002 | ||
| 318 | >> `resume' was checking the wrong value for stack overflow | ||
| 319 | (by Maik Zimmermann; since 5.0b) | ||
| 320 | |||
| 321 | ** ldo.c | ||
| 322 | Thu Jan 23 11:29:06 UTC 2003 | ||
| 323 | >> error during garbage collection in luaD_protectedparser is not being | ||
| 324 | >> protected | ||
| 325 | (by Benoit Germain; since 5.0a) | ||
| 326 | |||
| 327 | ** ldo.c (and others) | ||
| 328 | Fri Feb 28 14:20:33 EST 2003 | ||
| 329 | >> GC metamethod calls could mess C/Lua stack syncronization | ||
| 330 | (by Roberto; since 5.0b) | ||
| 331 | |||
| 332 | ** lzio.h/zlio.c | ||
| 333 | Thu Mar 20 11:40:12 EST 2003 | ||
| 334 | >> zio mixes a 255 as first char in a buffer with EOZ | ||
| 335 | (by lhf; since 5.0a) | ||
| 336 | |||
| 337 | |||
| 338 | |||
| 339 | --]=] | ||
| 340 | ----------------------------------------------------------------- | ||
| 341 | -- Lua 5.0 (final) | ||
| 342 | |||
| 343 | Bug{ | ||
| 344 | what = [[lua_closethread exists only in the manual]], | ||
| 345 | report = [[by Nguyen Binh, 28/04/2003]], | ||
| 346 | patch = [[no patch; the manual is wrong]], | ||
| 347 | } | ||
| 348 | |||
| 349 | |||
| 350 | Bug{ | ||
| 351 | what = [[attempt to resume a running coroutine crashes Lua]], | ||
| 352 | example = [[ | ||
| 353 | function co_func (current_co) | ||
| 354 | coroutine.resume(co) | ||
| 355 | end | ||
| 356 | co = coroutine.create(co_func) | ||
| 357 | coroutine.resume(co) | ||
| 358 | coroutine.resume(co) --> seg. fault | ||
| 359 | ]], | ||
| 360 | report = [[by Alex Bilyk, 09/05/2003]], | ||
| 361 | patch = [[ | ||
| 362 | * ldo.c: | ||
| 363 | 325,326c325 | ||
| 364 | < if (nargs >= L->top - L->base) | ||
| 365 | < luaG_runerror(L, "cannot resume dead coroutine"); | ||
| 366 | --- | ||
| 367 | > lua_assert(nargs < L->top - L->base); | ||
| 368 | 329c328,329 | ||
| 369 | < else if (ci->state & CI_YIELD) { /* inside a yield? */ | ||
| 370 | --- | ||
| 371 | > else { /* inside a yield */ | ||
| 372 | > lua_assert(ci->state & CI_YIELD); | ||
| 373 | 344,345d343 | ||
| 374 | < else | ||
| 375 | < luaG_runerror(L, "cannot resume non-suspended coroutine"); | ||
| 376 | 351a350,358 | ||
| 377 | > static int resume_error (lua_State *L, const char *msg) { | ||
| 378 | > L->top = L->ci->base; | ||
| 379 | > setsvalue2s(L->top, luaS_new(L, msg)); | ||
| 380 | > incr_top(L); | ||
| 381 | > lua_unlock(L); | ||
| 382 | > return LUA_ERRRUN; | ||
| 383 | > } | ||
| 384 | > | ||
| 385 | > | ||
| 386 | 355a363,368 | ||
| 387 | > if (L->ci == L->base_ci) { | ||
| 388 | > if (nargs >= L->top - L->base) | ||
| 389 | > return resume_error(L, "cannot resume dead coroutine"); | ||
| 390 | > } | ||
| 391 | > else if (!(L->ci->state & CI_YIELD)) /* not inside a yield? */ | ||
| 392 | > return resume_error(L, "cannot resume non-suspended coroutine"); | ||
| 393 | ]], | ||
| 394 | } | ||
| 395 | |||
| 396 | |||
| 397 | Bug{ | ||
| 398 | what = [[file:close cannot be called without a file. (results in seg fault)]], | ||
| 399 | example = [[ | ||
| 400 | > io.stdin.close() -- correct call shold be io.stdin:close() | ||
| 401 | ]], | ||
| 402 | report = [[by Tuomo Valkonen, 27/05/2003]], | ||
| 403 | patch = [[ | ||
| 404 | * liolib.c: | ||
| 405 | 161c161 | ||
| 406 | < if (lua_isnone(L, 1)) { | ||
| 407 | --- | ||
| 408 | > if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) { | ||
| 409 | ]], --}} | ||
| 410 | } | ||
| 411 | |||
| 412 | |||
| 413 | Bug{ | ||
| 414 | what = [[C functions also may have stacks larger than current top]], | ||
| 415 | example = [[ | ||
| 416 | Must recompile lua with a change in lua.c and with lua_assert defined: | ||
| 417 | * lua.c: | ||
| 418 | 381a382 | ||
| 419 | > lua_checkstack(l, 1000); | ||
| 420 | ]], | ||
| 421 | report = [[Alex Bilyk, 09/06/2003]], | ||
| 422 | patch = [[ | ||
| 423 | * lgc.c: | ||
| 424 | 247c247 | ||
| 425 | < if (!(ci->state & CI_C) && lim < ci->top) | ||
| 426 | --- | ||
| 427 | > if (lim < ci->top) | ||
| 428 | ]], | ||
| 429 | } | ||
| 430 | |||
| 431 | |||
| 432 | Bug{ | ||
| 433 | what = [[`pc' address is invalidated when a coroutine is suspended]], | ||
| 434 | example = [[ | ||
| 435 | function g(x) | ||
| 436 | coroutine.yield(x) | ||
| 437 | end | ||
| 438 | |||
| 439 | function f (i) | ||
| 440 | debug.sethook(print, "l") | ||
| 441 | for j=1,1000 do | ||
| 442 | g(i+j) | ||
| 443 | end | ||
| 444 | end | ||
| 445 | |||
| 446 | co = coroutine.wrap(f) | ||
| 447 | co(10) | ||
| 448 | pcall(co) | ||
| 449 | pcall(co) | ||
| 450 | ]], | ||
| 451 | report = [[Nick Trout, 07/07/2003]], | ||
| 452 | patch = [[ | ||
| 453 | * lvm.c: | ||
| 454 | 402,403c402,403 | ||
| 455 | < L->ci->u.l.pc = &pc; | ||
| 456 | < if (L->hookmask & LUA_MASKCALL) | ||
| 457 | --- | ||
| 458 | > if (L->hookmask & LUA_MASKCALL) { | ||
| 459 | > L->ci->u.l.pc = &pc; | ||
| 460 | 404a405 | ||
| 461 | > } | ||
| 462 | 405a407 | ||
| 463 | > L->ci->u.l.pc = &pc; | ||
| 464 | 676,678c678 | ||
| 465 | < lua_assert(ci->u.l.pc == &pc && | ||
| 466 | < ttisfunction(ci->base - 1) && | ||
| 467 | < (ci->state & CI_SAVEDPC)); | ||
| 468 | --- | ||
| 469 | > lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); | ||
| 470 | ]] | ||
| 471 | } | ||
| 472 | |||
| 473 | |||
| 474 | Bug{ | ||
| 475 | what = [[userdata to be collected still counts into new GC threshold, | ||
| 476 | increasing memory consumption]], | ||
| 477 | report = [[Roberto, 25/07/2003]], | ||
| 478 | example = [[ | ||
| 479 | a = newproxy(true) | ||
| 480 | getmetatable(a).__gc = function () end | ||
| 481 | for i=1,10000000 do | ||
| 482 | newproxy(a) | ||
| 483 | if math.mod(i, 10000) == 0 then print(gcinfo()) end | ||
| 484 | end | ||
| 485 | ]], | ||
| 486 | patch = [[ | ||
| 487 | * lgc.h: | ||
| 488 | 18c18 | ||
| 489 | < void luaC_separateudata (lua_State *L); | ||
| 490 | --- | ||
| 491 | > size_t luaC_separateudata (lua_State *L); | ||
| 492 | |||
| 493 | * lgc.c: | ||
| 494 | 113c113,114 | ||
| 495 | < void luaC_separateudata (lua_State *L) { | ||
| 496 | --- | ||
| 497 | > size_t luaC_separateudata (lua_State *L) { | ||
| 498 | > size_t deadmem = 0; | ||
| 499 | 127a129 | ||
| 500 | > deadmem += sizeudata(gcotou(curr)->uv.len); | ||
| 501 | 136a139 | ||
| 502 | > return deadmem; | ||
| 503 | 390c393 | ||
| 504 | < static void checkSizes (lua_State *L) { | ||
| 505 | --- | ||
| 506 | > static void checkSizes (lua_State *L, size_t deadmem) { | ||
| 507 | 400c403 | ||
| 508 | < G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ | ||
| 509 | --- | ||
| 510 | > G(L)->GCthreshold = 2*G(L)->nblocks - deadmem; /* new threshold */ | ||
| 511 | 454c457,458 | ||
| 512 | < static void mark (lua_State *L) { | ||
| 513 | --- | ||
| 514 | > static size_t mark (lua_State *L) { | ||
| 515 | > size_t deadmem; | ||
| 516 | 467c471 | ||
| 517 | < luaC_separateudata(L); /* separate userdata to be preserved */ | ||
| 518 | --- | ||
| 519 | > deadmem = luaC_separateudata(L); /* separate userdata to be preserved */ | ||
| 520 | 475a480 | ||
| 521 | > return deadmem; | ||
| 522 | 480c485 | ||
| 523 | < mark(L); | ||
| 524 | --- | ||
| 525 | > size_t deadmem = mark(L); | ||
| 526 | 482c487 | ||
| 527 | < checkSizes(L); | ||
| 528 | --- | ||
| 529 | > checkSizes(L, deadmem); | ||
| 530 | ]] | ||
| 531 | } | ||
| 532 | |||
| 533 | Bug{ | ||
| 534 | what=[[IBM AS400 (OS400) has sizeof(void *)==16, and a `%p' may generate | ||
| 535 | up to 60 characters in a `printf'. That causes a buffer overflow in | ||
| 536 | `tostring'.]], | ||
| 537 | |||
| 538 | report = [[David Burgess, 25/08/2003]], | ||
| 539 | |||
| 540 | example = [[print{}; (in an AS400 machine)]], | ||
| 541 | |||
| 542 | patch = [[ | ||
| 543 | * liolib.c: | ||
| 544 | 178c178 | ||
| 545 | < char buff[32]; | ||
| 546 | --- | ||
| 547 | > char buff[128]; | ||
| 548 | |||
| 549 | * lbaselib.c: | ||
| 550 | 327c327 | ||
| 551 | < char buff[64]; | ||
| 552 | --- | ||
| 553 | > char buff[128]; | ||
| 554 | ]] | ||
| 555 | } | ||
| 556 | |||
| 557 | |||
| 558 | Bug{ | ||
| 559 | what = [[syntax `local function' does not increment stack size]], | ||
| 560 | |||
| 561 | report = [[Rici Lake, 26/09/2003]], | ||
| 562 | |||
| 563 | example = [[ | ||
| 564 | -- must run this with precompiled code | ||
| 565 | local a,b,c | ||
| 566 | local function d () end | ||
| 567 | ]], | ||
| 568 | |||
| 569 | patch = [[ | ||
| 570 | * lparser.c: | ||
| 571 | 1143a1144 | ||
| 572 | > FuncState *fs = ls->fs; | ||
| 573 | 1145c1146,1147 | ||
| 574 | < init_exp(&v, VLOCAL, ls->fs->freereg++); | ||
| 575 | --- | ||
| 576 | > init_exp(&v, VLOCAL, fs->freereg); | ||
| 577 | > luaK_reserveregs(fs, 1); | ||
| 578 | 1148c1150,1152 | ||
| 579 | < luaK_storevar(ls->fs, &v, &b); | ||
| 580 | --- | ||
| 581 | > luaK_storevar(fs, &v, &b); | ||
| 582 | > /* debug information will only see the variable after this point! */ | ||
| 583 | > getlocvar(fs, fs->nactvar - 1).startpc = fs->pc; | ||
| 584 | ]], | ||
| 585 | |||
| 586 | } | ||
| 587 | |||
| 588 | |||
| 589 | Bug{ | ||
| 590 | |||
| 591 | what = [[count hook may be called without being set]], | ||
| 592 | |||
| 593 | report = [[Andreas Stenius, 06/10/2003]], | ||
| 594 | |||
| 595 | example = [[ | ||
| 596 | set your hooks with | ||
| 597 | |||
| 598 | lua_sethook(L, my_hook, LUA_MASKLINE | LUA_MASKRET, 1); | ||
| 599 | |||
| 600 | (It is weird to use a count > 0 without setting the count hook, | ||
| 601 | but it is not wrong.) | ||
| 602 | ]], | ||
| 603 | |||
| 604 | patch = [[ | ||
| 605 | * lvm.c: | ||
| 606 | 69c69 | ||
| 607 | < if (mask > LUA_MASKLINE) { /* instruction-hook set? */ | ||
| 608 | --- | ||
| 609 | > if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ | ||
| 610 | ]], | ||
| 611 | |||
| 612 | } | ||
| 613 | |||
| 614 | |||
| 615 | Bug{ | ||
| 616 | |||
| 617 | what = [[`dofile' eats one return value when called without arguments]], | ||
| 618 | |||
| 619 | report = [[Frederico Abraham, 15/01/2004]], | ||
| 620 | |||
| 621 | example = [[ | ||
| 622 | a,b = dofile() --< here you enter `return 1,2,3 <eof>' | ||
| 623 | print(a,b) --> 2 3 (should be 1 and 2) | ||
| 624 | ]], | ||
| 625 | |||
| 626 | patch = [[ | ||
| 627 | * lbaselib.c: | ||
| 628 | 313a314 | ||
| 629 | > int n = lua_gettop(L); | ||
| 630 | 317c318 | ||
| 631 | < return lua_gettop(L) - 1; | ||
| 632 | --- | ||
| 633 | > return lua_gettop(L) - n; | ||
| 634 | ]], | ||
| 635 | |||
| 636 | } | ||
| 637 | |||
| 638 | |||
| 639 | |||
| 640 | ----------------------------------------------------------------- | ||
| 641 | -- Lua 5.0.2 | ||
| 642 | |||
| 643 | Bug{ | ||
| 644 | what = [[string concatenation may cause arithmetic overflow, leading | ||
| 645 | to a buffer overflow]], | ||
| 646 | |||
| 647 | report = [[Rici Lake, 20/05/2004]], | ||
| 648 | |||
| 649 | example = [[ | ||
| 650 | longs = string.rep("\0", 2^25) | ||
| 651 | function catter(i) | ||
| 652 | return assert(loadstring( | ||
| 653 | string.format("return function(a) return a%s end", | ||
| 654 | string.rep("..a", i-1))))() | ||
| 655 | end | ||
| 656 | rep129 = catter(129) | ||
| 657 | rep129(longs) | ||
| 658 | ]], | ||
| 659 | |||
| 660 | patch = [[ | ||
| 661 | * lvm.c: | ||
| 662 | @@ -321,15 +321,15 @@ | ||
| 663 | luaG_concaterror(L, top-2, top-1); | ||
| 664 | } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */ | ||
| 665 | /* at least two string values; get as many as possible */ | ||
| 666 | - lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + | ||
| 667 | - cast(lu_mem, tsvalue(top-2)->tsv.len); | ||
| 668 | + size_t tl = tsvalue(top-1)->tsv.len; | ||
| 669 | char *buffer; | ||
| 670 | int i; | ||
| 671 | - while (n < total && tostring(L, top-n-1)) { /* collect total length */ | ||
| 672 | - tl += tsvalue(top-n-1)->tsv.len; | ||
| 673 | - n++; | ||
| 674 | + /* collect total length */ | ||
| 675 | + for (n = 1; n < total && tostring(L, top-n-1); n++) { | ||
| 676 | + size_t l = tsvalue(top-n-1)->tsv.len; | ||
| 677 | + if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); | ||
| 678 | + tl += l; | ||
| 679 | } | ||
| 680 | - if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); | ||
| 681 | buffer = luaZ_openspace(L, &G(L)->buff, tl); | ||
| 682 | tl = 0; | ||
| 683 | for (i=n; i>0; i--) { /* concat all strings */ | ||
| 684 | ]] | ||
| 685 | } | ||
| 686 | |||
| 687 | |||
| 688 | Bug{ | ||
| 689 | what = [[lua_getupvalue and setupvalue do not check for index too small]], | ||
| 690 | |||
| 691 | report = [[Mike Pall, ?/2004]], | ||
| 692 | |||
| 693 | example = [[debug.getupvalue(function() end, 0)]], | ||
| 694 | |||
| 695 | patch = [[ | ||
| 696 | * lapi.c | ||
| 697 | 941c941 | ||
| 698 | < if (n > f->c.nupvalues) return NULL; | ||
| 699 | --- | ||
| 700 | > if (!(1 <= n && n <= f->c.nupvalues)) return NULL; | ||
| 701 | 947c947 | ||
| 702 | < if (n > p->sizeupvalues) return NULL; | ||
| 703 | --- | ||
| 704 | > if (!(1 <= n && n <= p->sizeupvalues)) return NULL; | ||
| 705 | ]] | ||
| 706 | } | ||
| 707 | |||
| 708 | |||
| 709 | Bug{ | ||
| 710 | what = [[values holded in open upvalues of suspended threads may be | ||
| 711 | incorrectly collected]], | ||
| 712 | |||
| 713 | report = [[Spencer Schumann, 31/12/2004]], | ||
| 714 | |||
| 715 | example = [[ | ||
| 716 | local thread_id = 0 | ||
| 717 | local threads = {} | ||
| 718 | |||
| 719 | function fn(thread) | ||
| 720 | thread_id = thread_id + 1 | ||
| 721 | threads[thread_id] = function() | ||
| 722 | thread = nil | ||
| 723 | end | ||
| 724 | coroutine.yield() | ||
| 725 | end | ||
| 726 | |||
| 727 | while true do | ||
| 728 | local thread = coroutine.create(fn) | ||
| 729 | coroutine.resume(thread, thread) | ||
| 730 | end | ||
| 731 | ]], | ||
| 732 | |||
| 733 | patch = [[ | ||
| 734 | * lgc.c: | ||
| 735 | 221,224c221,222 | ||
| 736 | < if (!u->marked) { | ||
| 737 | < markobject(st, &u->value); | ||
| 738 | < u->marked = 1; | ||
| 739 | < } | ||
| 740 | --- | ||
| 741 | > markobject(st, u->v); | ||
| 742 | > u->marked = 1; | ||
| 743 | ]], | ||
| 744 | } | ||
| 745 | |||
| 746 | |||
| 747 | Bug{ | ||
| 748 | what = [[rawset/rawget do not ignore extra arguments]], | ||
| 749 | |||
| 750 | report = [[Romulo Bahiense, 11/03/2005]], | ||
| 751 | |||
| 752 | example = [[ | ||
| 753 | a = {} | ||
| 754 | rawset(a, 1, 2, 3) | ||
| 755 | print(a[1], a[2]) -- should be 2 and nil | ||
| 756 | ]], | ||
| 757 | |||
| 758 | patch = [[ | ||
| 759 | * lbaselib.c: | ||
| 760 | 175a176 | ||
| 761 | > lua_settop(L, 2); | ||
| 762 | 183a185 | ||
| 763 | > lua_settop(L, 3); | ||
| 764 | ]], | ||
| 765 | } | ||
| 766 | |||
| 767 | |||
| 768 | Bug{ | ||
| 769 | what = [[weak tables that survive one collection are never collected]], | ||
| 770 | |||
| 771 | report = [[Chromix, 02/01/2006]], | ||
| 772 | |||
| 773 | example = [[ | ||
| 774 | a = {} | ||
| 775 | print(gcinfo()) | ||
| 776 | for i = 1, 10000 do | ||
| 777 | a[i] = setmetatable({}, {__mode = "v"}) | ||
| 778 | end | ||
| 779 | collectgarbage() | ||
| 780 | a = nil | ||
| 781 | collectgarbage() | ||
| 782 | print(gcinfo()) | ||
| 783 | ]], | ||
| 784 | |||
| 785 | patch = [[ | ||
| 786 | * lgc.c | ||
| 787 | @@ -366,7 +366,7 @@ | ||
| 788 | GCObject *curr; | ||
| 789 | int count = 0; /* number of collected items */ | ||
| 790 | while ((curr = *p) != NULL) { | ||
| 791 | - if (curr->gch.marked > limit) { | ||
| 792 | + if ((curr->gch.marked & ~(KEYWEAK | VALUEWEAK)) > limit) { | ||
| 793 | unmark(curr); | ||
| 794 | p = &curr->gch.next; | ||
| 795 | } | ||
| 796 | ]], | ||
| 797 | |||
| 798 | } | ||
| 799 | |||
| 800 | |||
| 801 | Bug{ | ||
| 802 | what = [[Some "not not exp" may not result in boolean values]], | ||
| 803 | report = [[]], | ||
| 804 | since = [[4.0]], | ||
| 805 | example = [[ | ||
| 806 | -- should print false, but prints nil | ||
| 807 | print(not not (nil and 4)) | ||
| 808 | ]], | ||
| 809 | patch = [[]], | ||
| 810 | } | ||
| 811 | |||
| 812 | |||
| 813 | Bug{ | ||
| 814 | what = [[On some machines, closing a "piped file" (created with io.popen) | ||
| 815 | may crash Lua]], | ||
| 816 | report = [[]], | ||
| 817 | since = [[5.0]], | ||
| 818 | example = [[ | ||
| 819 | -- only on some machines | ||
| 820 | f = io.popen("ls") | ||
| 821 | f:close() | ||
| 822 | ]], | ||
| 823 | patch = [[]], | ||
| 824 | } | ||
| 825 | |||
| 826 | |||
| 827 | |||
| 828 | ----------------------------------------------------------------- | ||
| 829 | -- Lua 5.1 | ||
| 830 | |||
| 831 | Bug{ | ||
| 832 | what = [[In 16-bit machines, expressions and/or with numeric constants as the | ||
| 833 | right operand may result in weird values]], | ||
| 834 | |||
| 835 | report = [[Andreas Stenius/Kein-Hong Man, 15/03/2006]], | ||
| 836 | |||
| 837 | example = [[ | ||
| 838 | print(false or 0) -- on 16-bit machines | ||
| 839 | ]], | ||
| 840 | |||
| 841 | patch = [[ | ||
| 842 | * lcode.c: | ||
| 843 | @@ -731,17 +731,15 @@ | ||
| 844 | case OPR_AND: { | ||
| 845 | lua_assert(e1->t == NO_JUMP); /* list must be closed */ | ||
| 846 | luaK_dischargevars(fs, e2); | ||
| 847 | - luaK_concat(fs, &e1->f, e2->f); | ||
| 848 | - e1->k = e2->k; e1->u.s.info = e2->u.s.info; | ||
| 849 | - e1->u.s.aux = e2->u.s.aux; e1->t = e2->t; | ||
| 850 | + luaK_concat(fs, &e2->f, e1->f); | ||
| 851 | + *e1 = *e2; | ||
| 852 | break; | ||
| 853 | } | ||
| 854 | case OPR_OR: { | ||
| 855 | lua_assert(e1->f == NO_JUMP); /* list must be closed */ | ||
| 856 | luaK_dischargevars(fs, e2); | ||
| 857 | - luaK_concat(fs, &e1->t, e2->t); | ||
| 858 | - e1->k = e2->k; e1->u.s.info = e2->u.s.info; | ||
| 859 | - e1->u.s.aux = e2->u.s.aux; e1->f = e2->f; | ||
| 860 | + luaK_concat(fs, &e2->t, e1->t); | ||
| 861 | + *e1 = *e2; | ||
| 862 | break; | ||
| 863 | } | ||
| 864 | ]], | ||
| 865 | |||
| 866 | } | ||
| 867 | |||
| 868 | |||
| 869 | Bug{ | ||
| 870 | what = [[luaL_checkudata may produce wrong error message]], | ||
| 871 | |||
| 872 | report = [[Greg Falcon, 21/03/2006]], | ||
| 873 | |||
| 874 | example = [[ | ||
| 875 | getmetatable(io.stdin).__gc() | ||
| 876 | --> bad argument #1 to '__gc' (FILE* expected, got table) | ||
| 877 | ]], | ||
| 878 | |||
| 879 | patch = [[ | ||
| 880 | * lauxlib.c: | ||
| 881 | @@ -123,11 +123,17 @@ | ||
| 882 | |||
| 883 | LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { | ||
| 884 | void *p = lua_touserdata(L, ud); | ||
| 885 | - lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ | ||
| 886 | - if (p == NULL || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2)) | ||
| 887 | - luaL_typerror(L, ud, tname); | ||
| 888 | - lua_pop(L, 2); /* remove both metatables */ | ||
| 889 | - return p; | ||
| 890 | + if (p != NULL) { /* value is a userdata? */ | ||
| 891 | + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ | ||
| 892 | + lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ | ||
| 893 | + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ | ||
| 894 | + lua_pop(L, 2); /* remove both metatables */ | ||
| 895 | + return p; | ||
| 896 | + } | ||
| 897 | + } | ||
| 898 | + } | ||
| 899 | + luaL_typerror(L, ud, tname); /* else error */ | ||
| 900 | + return NULL; /* to avoid warnings */ | ||
| 901 | } | ||
| 902 | ]] | ||
| 903 | |||
| 904 | } | ||
| 905 | |||
| 906 | |||
| 907 | Bug{ | ||
| 908 | what = [[ | ||
| 909 | In Windows, | ||
| 910 | when Lua is used in an application that also uses DirectX, | ||
| 911 | it may present an erractic behavior. | ||
| 912 | THIS IS NOT A LUA BUG! | ||
| 913 | The problem is that DirectX violates an ABI that Lua depends on.]], | ||
| 914 | |||
| 915 | patch = [[ | ||
| 916 | The simplest solution is to use DirectX with | ||
| 917 | the D3DCREATE_FPU_PRESERVE flag. | ||
| 918 | |||
| 919 | Otherwise, you can change the definition of lua_number2int, | ||
| 920 | in luaconf.h, to this one: | ||
| 921 | #define lua_number2int(i,d) __asm fld d __asm fistp i | ||
| 922 | ]], | ||
| 923 | |||
| 924 | } | ||
| 925 | |||
| 926 | |||
| 927 | Bug{ | ||
| 928 | what = [[option '%q' in string.format does not handle '\r' correctly.]], | ||
| 929 | |||
| 930 | example = [[ | ||
| 931 | local s = "a string with \r and \n and \r\n and \n\r" | ||
| 932 | local c = string.format("return %q", s) | ||
| 933 | assert(assert(loadstring(c))() == s) | ||
| 934 | ]], | ||
| 935 | |||
| 936 | patch = [[ | ||
| 937 | * lstrlib.c: | ||
| 938 | @@ -703,6 +703,10 @@ | ||
| 939 | luaL_addchar(b, *s); | ||
| 940 | break; | ||
| 941 | } | ||
| 942 | + case '\r': { | ||
| 943 | + luaL_addlstring(b, "\\r", 2); | ||
| 944 | + break; | ||
| 945 | + } | ||
| 946 | case '\0': { | ||
| 947 | luaL_addlstring(b, "\\000", 4); | ||
| 948 | break; | ||
| 949 | ]], | ||
| 950 | |||
| 951 | } | ||
| 952 | |||
| 953 | |||
| 954 | Bug{ | ||
| 955 | what = [[lua_dostring/lua_dofile should return any values returned | ||
| 956 | by the chunk]], | ||
| 957 | |||
| 958 | patch = [[ | ||
| 959 | * lauxlib.h: | ||
| 960 | @@ -108,9 +108,11 @@ | ||
| 961 | |||
| 962 | #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) | ||
| 963 | |||
| 964 | -#define luaL_dofile(L, fn) (luaL_loadfile(L, fn) || lua_pcall(L, 0, 0, 0)) | ||
| 965 | +#define luaL_dofile(L, fn) \ | ||
| 966 | + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) | ||
| 967 | |||
| 968 | -#define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, 0, 0))+#define luaL_dostring(L, s) \ | ||
| 969 | + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) | ||
| 970 | |||
| 971 | #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) | ||
| 972 | ]], | ||
| 973 | |||
| 974 | } | ||
| 975 | |||
| 976 | |||
| 977 | Bug{ | ||
| 978 | |||
| 979 | what = [[garbage collector does not compensate enough for finalizers]], | ||
| 980 | |||
| 981 | patch = [[ | ||
| 982 | lgc.c: | ||
| 983 | @@ -322,4 +322,6 @@ | ||
| 984 | |||
| 985 | -static void propagateall (global_State *g) { | ||
| 986 | - while (g->gray) propagatemark(g); | ||
| 987 | +static size_t propagateall (global_State *g) { | ||
| 988 | + size_t m = 0; | ||
| 989 | + while (g->gray) m += propagatemark(g); | ||
| 990 | + return m; | ||
| 991 | } | ||
| 992 | @@ -542,3 +544,3 @@ | ||
| 993 | marktmu(g); /* mark `preserved' userdata */ | ||
| 994 | - propagateall(g); /* remark, to propagate `preserveness' */ | ||
| 995 | + udsize += propagateall(g); /* remark, to propagate `preserveness' */ | ||
| 996 | cleartable(g->weak); /* remove collected objects from weak tables */ | ||
| 997 | @@ -592,2 +594,4 @@ | ||
| 998 | GCTM(L); | ||
| 999 | + if (g->estimate > GCFINALIZECOST) | ||
| 1000 | + g->estimate -= GCFINALIZECOST; | ||
| 1001 | ]] | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | |||
| 1005 | Bug{ | ||
| 1006 | |||
| 1007 | what = [[debug hooks may get wrong when mixed with coroutines]], | ||
| 1008 | |||
| 1009 | report = [[by Ivko Stanilov, 03/06/2006]], | ||
| 1010 | |||
| 1011 | example = [[ | ||
| 1012 | co = coroutine.create(function (a,b) | ||
| 1013 | coroutine.yield(a, b) | ||
| 1014 | return b, "end" | ||
| 1015 | end) | ||
| 1016 | |||
| 1017 | debug.sethook(co, function() end, "lcr") | ||
| 1018 | coroutine.resume(co, 100, 2000) | ||
| 1019 | coroutine.resume(co, 100, 2000) | ||
| 1020 | ]], | ||
| 1021 | |||
| 1022 | patch = [[ | ||
| 1023 | * ldo.c: | ||
| 1024 | @@ -389,6 +389,7 @@ | ||
| 1025 | return; | ||
| 1026 | } | ||
| 1027 | else { /* resuming from previous yield */ | ||
| 1028 | + L->status = 0; | ||
| 1029 | if (!f_isLua(ci)) { /* `common' yield? */ | ||
| 1030 | /* finish interrupted execution of `OP_CALL' */ | ||
| 1031 | lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || | ||
| 1032 | @@ -399,7 +400,6 @@ | ||
| 1033 | else /* yielded inside a hook: just continue its execution */ | ||
| 1034 | L->base = L->ci->base; | ||
| 1035 | } | ||
| 1036 | - L->status = 0; | ||
| 1037 | luaV_execute(L, cast_int(L->ci - L->base_ci)); | ||
| 1038 | } | ||
| 1039 | ]], | ||
| 1040 | |||
| 1041 | } | ||
| 1042 | |||
| 1043 | |||
| 1044 | |||
| 1045 | ----------------------------------------------------------------- | ||
| 1046 | -- Lua 5.1.1 | ||
| 1047 | |||
| 1048 | Bug{ | ||
| 1049 | what = [[list constructors have wrong limit]], | ||
| 1050 | |||
| 1051 | report = [[by Norman Ramsey, June 2006]], | ||
| 1052 | |||
| 1053 | since = "5.1", | ||
| 1054 | |||
| 1055 | example = [[ | ||
| 1056 | a = {} | ||
| 1057 | a[1] = "x={1" | ||
| 1058 | for i = 2, 2^20 do | ||
| 1059 | a[i] = 1 | ||
| 1060 | end | ||
| 1061 | a[#a + 1] = "}" | ||
| 1062 | s = table.concat(a, ",") | ||
| 1063 | assert(loadstring(s))() | ||
| 1064 | print(#x) | ||
| 1065 | ]], | ||
| 1066 | |||
| 1067 | patch = [[ | ||
| 1068 | * lparser.c: | ||
| 1069 | @@ -489,7 +489,7 @@ | ||
| 1070 | |||
| 1071 | static void listfield (LexState *ls, struct ConsControl *cc) { | ||
| 1072 | expr(ls, &cc->v); | ||
| 1073 | - luaY_checklimit(ls->fs, cc->na, MAXARG_Bx, "items in a constructor"); | ||
| 1074 | + luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); | ||
| 1075 | cc->na++; | ||
| 1076 | cc->tostore++; | ||
| 1077 | } | ||
| 1078 | ]], | ||
| 1079 | |||
| 1080 | } | ||
| 1081 | |||
| 1082 | |||
| 1083 | Bug{ | ||
| 1084 | what = [[wrong message error in some cases involving closures]], | ||
| 1085 | |||
| 1086 | report = [[Shmuel Zeigerman, on 07/2006]], | ||
| 1087 | |||
| 1088 | since = "5.1", | ||
| 1089 | |||
| 1090 | example = [[ | ||
| 1091 | local Var | ||
| 1092 | local function main() | ||
| 1093 | NoSuchName (function() Var=0 end) | ||
| 1094 | end | ||
| 1095 | main() | ||
| 1096 | --> lua5.1: temp:3: attempt to call upvalue 'Var' (a nil value) | ||
| 1097 | ]], | ||
| 1098 | |||
| 1099 | patch = [[ | ||
| 1100 | *ldebug.c: | ||
| 1101 | @@ -435,14 +435,16 @@ | ||
| 1102 | break; | ||
| 1103 | } | ||
| 1104 | case OP_CLOSURE: { | ||
| 1105 | - int nup; | ||
| 1106 | + int nup, j; | ||
| 1107 | check(b < pt->sizep); | ||
| 1108 | nup = pt->p[b]->nups; | ||
| 1109 | check(pc + nup < pt->sizecode); | ||
| 1110 | - for (; nup>0; nup--) { | ||
| 1111 | - OpCode op1 = GET_OPCODE(pt->code[pc+nup]); | ||
| 1112 | + for (j = 1; j <= nup; j++) { | ||
| 1113 | + OpCode op1 = GET_OPCODE(pt->code[pc + j]); | ||
| 1114 | check(op1 == OP_GETUPVAL || op1 == OP_MOVE); | ||
| 1115 | } | ||
| 1116 | + if (reg != NO_REG) /* tracing? */ | ||
| 1117 | + pc += nup; /* do not 'execute' these pseudo-instructions */ | ||
| 1118 | break; | ||
| 1119 | } | ||
| 1120 | case OP_VARARG: { | ||
| 1121 | ]], | ||
| 1122 | |||
| 1123 | } | ||
| 1124 | |||
| 1125 | |||
| 1126 | Bug{ | ||
| 1127 | what = [[string.format("%") may read past the string]], | ||
| 1128 | report = [[Roberto, on 09/2006]], | ||
| 1129 | since = [[5.0]], | ||
| 1130 | example = [[print(string.format("%"))]], | ||
| 1131 | patch = [[ | ||
| 1132 | *lstrlib.c: | ||
| 1133 | @@ -723,7 +723,7 @@ | ||
| 1134 | |||
| 1135 | static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; | ||
| 1136 | - while (strchr(FLAGS, *p)) p++; /* skip flags */ | ||
| 1137 | + while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ | ||
| 1138 | if ((size_t)(p - strfrmt) >= sizeof(FLAGS)) | ||
| 1139 | luaL_error(L, "invalid format (repeated flags)"); | ||
| 1140 | if (isdigit(uchar(*p))) p++; /* skip width */ | ||
| 1141 | ]], | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | |||
| 1145 | Bug{ | ||
| 1146 | what = [[os.date throws an error when result is the empty string]], | ||
| 1147 | report = [[]], | ||
| 1148 | since = [[4.0]], | ||
| 1149 | example = [[print(os.date(""))]], | ||
| 1150 | patch = [[ | ||
| 1151 | *loslib.c: | ||
| 1152 | @@ -148,7 +148,18 @@ | ||
| 1153 | else { | ||
| 1154 | - char b[256]; | ||
| 1155 | - if (strftime(b, sizeof(b), s, stm)) | ||
| 1156 | - lua_pushstring(L, b); | ||
| 1157 | - else | ||
| 1158 | - return luaL_error(L, LUA_QL("date") " format too long"); | ||
| 1159 | + char cc[3]; | ||
| 1160 | + luaL_Buffer b; | ||
| 1161 | + cc[0] = '%'; cc[2] = '\0'; | ||
| 1162 | + luaL_buffinit(L, &b); | ||
| 1163 | + for (; *s; s++) { | ||
| 1164 | + if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ | ||
| 1165 | + luaL_addchar(&b, *s); | ||
| 1166 | + else { | ||
| 1167 | + size_t reslen; | ||
| 1168 | + char buff[200]; /* should be big enough for any conversion result */ | ||
| 1169 | + cc[1] = *(++s); | ||
| 1170 | + reslen = strftime(buff, sizeof(buff), cc, stm); | ||
| 1171 | + luaL_addlstring(&b, buff, reslen); | ||
| 1172 | + } | ||
| 1173 | + } | ||
| 1174 | + luaL_pushresult(&b); | ||
| 1175 | } | ||
| 1176 | ]], | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | |||
| 1180 | Bug{ | ||
| 1181 | what = [[setfenv accepts invalid 1st argument]], | ||
| 1182 | report = [[Doug Rogers, on 02/2007]], | ||
| 1183 | since = [[5.0]], | ||
| 1184 | example = [[setfenv(nil, {}) -- should throw an error]], | ||
| 1185 | patch = [[ | ||
| 1186 | *lbaselib.c: | ||
| 1187 | @@ -116,3 +116,3 @@ | ||
| 1188 | |||
| 1189 | -static void getfunc (lua_State *L) { | ||
| 1190 | +static void getfunc (lua_State *L, int opt) { | ||
| 1191 | if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); | ||
| 1192 | @@ -120,3 +120,3 @@ | ||
| 1193 | lua_Debug ar; | ||
| 1194 | - int level = luaL_optint(L, 1, 1); | ||
| 1195 | + int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); | ||
| 1196 | luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); | ||
| 1197 | @@ -133,3 +133,3 @@ | ||
| 1198 | static int luaB_getfenv (lua_State *L) { | ||
| 1199 | - getfunc(L); | ||
| 1200 | + getfunc(L, 1); | ||
| 1201 | if (lua_iscfunction(L, -1)) /* is a C function? */ | ||
| 1202 | @@ -144,3 +144,3 @@ | ||
| 1203 | luaL_checktype(L, 2, LUA_TTABLE); | ||
| 1204 | - getfunc(L); | ||
| 1205 | + getfunc(L, 0); | ||
| 1206 | lua_pushvalue(L, 2); | ||
| 1207 | ]], | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | |||
| 1211 | Bug{ | ||
| 1212 | what = [[wrong code for arithmetic expressions in some specific scenarios]], | ||
| 1213 | report = [[Thierry Grellier, on 01/2007]], | ||
| 1214 | since = [[5.1]], | ||
| 1215 | example = [[ | ||
| 1216 | -- use a large number of names (almost 256) | ||
| 1217 | v1=1; v2=1; v3=1; v4=1; v5=1; v6=1; v7=1; v8=1; v9=1; | ||
| 1218 | v10=1; v11=1; v12=1; v13=1; v14=1; v15=1; v16=1; v17=1; | ||
| 1219 | v18=1; v19=1; v20=1; v21=1; v22=1; v23=1; v24=1; v25=1; | ||
| 1220 | v26=1; v27=1; v28=1; v29=1; v30=1; v31=1; v32=1; v33=1; | ||
| 1221 | v34=1; v35=1; v36=1; v37=1; v38=1; v39=1; v40=1; v41=1; | ||
| 1222 | v42=1; v43=1; v44=1; v45=1; v46=1; v47=1; v48=1; v49=1; | ||
| 1223 | v50=1; v51=1; v52=1; v53=1; v54=1; v55=1; v56=1; v57=1; | ||
| 1224 | v58=1; v59=1; v60=1; v61=1; v62=1; v63=1; v64=1; v65=1; | ||
| 1225 | v66=1; v67=1; v68=1; v69=1; v70=1; v71=1; v72=1; v73=1; | ||
| 1226 | v74=1; v75=1; v76=1; v77=1; v78=1; v79=1; v80=1; v81=1; | ||
| 1227 | v82=1; v83=1; v84=1; v85=1; v86=1; v87=1; v88=1; v89=1; | ||
| 1228 | v90=1; v91=1; v92=1; v93=1; v94=1; v95=1; v96=1; v97=1; | ||
| 1229 | v98=1; v99=1; v100=1; v101=1; v102=1; v103=1; v104=1; v105=1; | ||
| 1230 | v106=1; v107=1; v108=1; v109=1; v110=1; v111=1; v112=1; v113=1; | ||
| 1231 | v114=1; v115=1; v116=1; v117=1; v118=1; v119=1; v120=1; v121=1; | ||
| 1232 | v122=1; v123=1; v124=1; v125=1; v126=1; v127=1; v128=1; v129=1; | ||
| 1233 | v130=1; v131=1; v132=1; v133=1; v134=1; v135=1; v136=1; v137=1; | ||
| 1234 | v138=1; v139=1; v140=1; v141=1; v142=1; v143=1; v144=1; v145=1; | ||
| 1235 | v146=1; v147=1; v148=1; v149=1; v150=1; v151=1; v152=1; v153=1; | ||
| 1236 | v154=1; v155=1; v156=1; v157=1; v158=1; v159=1; v160=1; v161=1; | ||
| 1237 | v162=1; v163=1; v164=1; v165=1; v166=1; v167=1; v168=1; v169=1; | ||
| 1238 | v170=1; v171=1; v172=1; v173=1; v174=1; v175=1; v176=1; v177=1; | ||
| 1239 | v178=1; v179=1; v180=1; v181=1; v182=1; v183=1; v184=1; v185=1; | ||
| 1240 | v186=1; v187=1; v188=1; v189=1; v190=1; v191=1; v192=1; v193=1; | ||
| 1241 | v194=1; v195=1; v196=1; v197=1; v198=1; v199=1; v200=1; v201=1; | ||
| 1242 | v202=1; v203=1; v204=1; v205=1; v206=1; v207=1; v208=1; v209=1; | ||
| 1243 | v210=1; v211=1; v212=1; v213=1; v214=1; v215=1; v216=1; v217=1; | ||
| 1244 | v218=1; v219=1; v220=1; v221=1; v222=1; v223=1; v224=1; v225=1; | ||
| 1245 | v226=1; v227=1; v228=1; v229=1; v230=1; v231=1; v232=1; v233=1; | ||
| 1246 | v234=1; v235=1; v236=1; v237=1; v238=1; v239=1; v240=1; v241=1; | ||
| 1247 | v242=1; v243=1; v244=1; v245=1; v246=1; v247=1; v248=1; v249=1; | ||
| 1248 | v250=1; | ||
| 1249 | v251={k1 = 1}; | ||
| 1250 | v252=1; | ||
| 1251 | print(2 * v251.k1, v251.k1 * 2); -- 2 2, OK | ||
| 1252 | v253=1; | ||
| 1253 | print(2 * v251.k1, v251.k1 * 2); -- 1 2, ??? | ||
| 1254 | ]], | ||
| 1255 | patch = [[ | ||
| 1256 | *lcode.c: | ||
| 1257 | @@ -657,10 +657,16 @@ | ||
| 1258 | if (constfolding(op, e1, e2)) | ||
| 1259 | return; | ||
| 1260 | else { | ||
| 1261 | - int o1 = luaK_exp2RK(fs, e1); | ||
| 1262 | int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; | ||
| 1263 | - freeexp(fs, e2); | ||
| 1264 | - freeexp(fs, e1); | ||
| 1265 | + int o1 = luaK_exp2RK(fs, e1); | ||
| 1266 | + if (o1 > o2) { | ||
| 1267 | + freeexp(fs, e1); | ||
| 1268 | + freeexp(fs, e2); | ||
| 1269 | + } | ||
| 1270 | + else { | ||
| 1271 | + freeexp(fs, e2); | ||
| 1272 | + freeexp(fs, e1); | ||
| 1273 | + } | ||
| 1274 | e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); | ||
| 1275 | e1->k = VRELOCABLE; | ||
| 1276 | } | ||
| 1277 | @@ -718,10 +724,15 @@ | ||
| 1278 | luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ | ||
| 1279 | break; | ||
| 1280 | } | ||
| 1281 | - default: { | ||
| 1282 | + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: | ||
| 1283 | + case OPR_MOD: case OPR_POW: { | ||
| 1284 | if (!isnumeral(v)) luaK_exp2RK(fs, v); | ||
| 1285 | break; | ||
| 1286 | } | ||
| 1287 | + default: { | ||
| 1288 | + luaK_exp2RK(fs, v); | ||
| 1289 | + break; | ||
| 1290 | + } | ||
| 1291 | } | ||
| 1292 | } | ||
| 1293 | ]], | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | Bug{ | ||
| 1297 | what = [[assignment of nil to parameter may be optimized away]], | ||
| 1298 | report = [[Thomas Lauer, on 03/2007]], | ||
| 1299 | since = [[5.1]], | ||
| 1300 | example = [[ | ||
| 1301 | function f (a) | ||
| 1302 | a=nil | ||
| 1303 | return a | ||
| 1304 | end | ||
| 1305 | |||
| 1306 | print(f("test")) | ||
| 1307 | ]], | ||
| 1308 | patch = [[ | ||
| 1309 | *lcode.c: | ||
| 1310 | @@ -35,16 +35,20 @@ | ||
| 1311 | void luaK_nil (FuncState *fs, int from, int n) { | ||
| 1312 | Instruction *previous; | ||
| 1313 | if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ | ||
| 1314 | - if (fs->pc == 0) /* function start? */ | ||
| 1315 | - return; /* positions are already clean */ | ||
| 1316 | - previous = &fs->f->code[fs->pc-1]; | ||
| 1317 | - if (GET_OPCODE(*previous) == OP_LOADNIL) { | ||
| 1318 | - int pfrom = GETARG_A(*previous); | ||
| 1319 | - int pto = GETARG_B(*previous); | ||
| 1320 | - if (pfrom <= from && from <= pto+1) { /* can connect both? */ | ||
| 1321 | - if (from+n-1 > pto) | ||
| 1322 | - SETARG_B(*previous, from+n-1); | ||
| 1323 | - return; | ||
| 1324 | + if (fs->pc == 0) { /* function start? */ | ||
| 1325 | + if (from >= fs->nactvar) | ||
| 1326 | + return; /* positions are already clean */ | ||
| 1327 | + } | ||
| 1328 | + else { | ||
| 1329 | + previous = &fs->f->code[fs->pc-1]; | ||
| 1330 | + if (GET_OPCODE(*previous) == OP_LOADNIL) { | ||
| 1331 | + int pfrom = GETARG_A(*previous); | ||
| 1332 | + int pto = GETARG_B(*previous); | ||
| 1333 | + if (pfrom <= from && from <= pto+1) { /* can connect both? */ | ||
| 1334 | + if (from+n-1 > pto) | ||
| 1335 | + SETARG_B(*previous, from+n-1); | ||
| 1336 | + return; | ||
| 1337 | + } | ||
| 1338 | } | ||
| 1339 | } | ||
| 1340 | } | ||
| 1341 | ]], | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | |||
| 1345 | Bug{ | ||
| 1346 | what = [[__concat metamethod converts numbers to strings]], | ||
| 1347 | report = [[Paul Winwood, on 12/2006]], | ||
| 1348 | since = [[5.0]], | ||
| 1349 | example = [[ | ||
| 1350 | a = {} | ||
| 1351 | setmetatable(a, {__concat = function (a,b) print(type(a), type(b)) end}) | ||
| 1352 | a = 4 .. a | ||
| 1353 | ]], | ||
| 1354 | patch = [[ | ||
| 1355 | *lvm.c: | ||
| 1356 | @@ -281,10 +281,12 @@ | ||
| 1357 | do { | ||
| 1358 | StkId top = L->base + last + 1; | ||
| 1359 | int n = 2; /* number of elements handled in this pass (at least 2) */ | ||
| 1360 | - if (!tostring(L, top-2) || !tostring(L, top-1)) { | ||
| 1361 | + if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { | ||
| 1362 | if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) | ||
| 1363 | luaG_concaterror(L, top-2, top-1); | ||
| 1364 | - } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ | ||
| 1365 | + } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ | ||
| 1366 | + (void)tostring(L, top - 2); /* result is first op (as string) */ | ||
| 1367 | + else { | ||
| 1368 | /* at least two string values; get as many as possible */ | ||
| 1369 | size_t tl = tsvalue(top-1)->len; | ||
| 1370 | char *buffer; | ||
| 1371 | ]], | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | |||
| 1375 | Bug{ | ||
| 1376 | what = [[As a library, loadlib.c should not access Lua internals | ||
| 1377 | (via lobject.h)]], | ||
| 1378 | report = [[Jérôme Vuarand, on 03/2007]], | ||
| 1379 | since = [[5.0]], | ||
| 1380 | example = [[the bug has no effect on external behavior]], | ||
| 1381 | patch = [[remove the '#include "lobject.h" and use | ||
| 1382 | 'lua_pushfstring' instead of 'luaO_pushfstring']], | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | |||
| 1386 | |||
| 1387 | ----------------------------------------------------------------- | ||
| 1388 | -- Lua 5.1.2 | ||
| 1389 | |||
| 1390 | Bug{ | ||
| 1391 | what = [[Lua may close standard files, | ||
| 1392 | which then may be used by C]], | ||
| 1393 | report = [[David Manura/Ross Berteig, on 04/2007]], | ||
| 1394 | since = [[]], | ||
| 1395 | example = [[ | ||
| 1396 | io.close(io.stderr) | ||
| 1397 | -- in some systems, following attempts to write to 'stderr' may crash | ||
| 1398 | a = a + 1 | ||
| 1399 | ]], | ||
| 1400 | patch = [[ | ||
| 1401 | ]], | ||
| 1402 | } | ||
| 1403 | |||
| 1404 | Bug{ | ||
| 1405 | what = [[code generated for "-nil", "-true", and "-false" is wrong]], | ||
| 1406 | report = [[David Manura/Rici Lake, on 04/2007]], | ||
| 1407 | since = [[5.1]], | ||
| 1408 | example = [[print(-nil)]], | ||
| 1409 | patch = [[ | ||
| 1410 | lcode.c: | ||
| 1411 | @@ -699,7 +699,7 @@ | ||
| 1412 | e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; | ||
| 1413 | switch (op) { | ||
| 1414 | case OPR_MINUS: { | ||
| 1415 | - if (e->k == VK) | ||
| 1416 | + if (!isnumeral(e)) | ||
| 1417 | luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ | ||
| 1418 | codearith(fs, OP_UNM, e, &e2); | ||
| 1419 | break; | ||
| 1420 | ]], | ||
| 1421 | } | ||
| 1422 | |||
| 1423 | Bug{ | ||
| 1424 | what = [[Count hook may be called without being set.]], | ||
| 1425 | report = [[Mike Pall, on 05/2007]], | ||
| 1426 | since = [[?]], | ||
| 1427 | example = [[]], | ||
| 1428 | patch = [[ | ||
| 1429 | lvm.c: | ||
| 1430 | @@ -61,11 +61,9 @@ | ||
| 1431 | lu_byte mask = L->hookmask; | ||
| 1432 | const Instruction *oldpc = L->savedpc; | ||
| 1433 | L->savedpc = pc; | ||
| 1434 | - if (mask > LUA_MASKLINE) { /* instruction-hook set? */ | ||
| 1435 | - if (L->hookcount == 0) { | ||
| 1436 | - resethookcount(L); | ||
| 1437 | - luaD_callhook(L, LUA_HOOKCOUNT, -1); | ||
| 1438 | - } | ||
| 1439 | + if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { | ||
| 1440 | + resethookcount(L); | ||
| 1441 | + luaD_callhook(L, LUA_HOOKCOUNT, -1); | ||
| 1442 | } | ||
| 1443 | if (mask & LUA_MASKLINE) { | ||
| 1444 | Proto *p = ci_func(L->ci)->l.p; | ||
| 1445 | ]], | ||
| 1446 | } | ||
| 1447 | |||
| 1448 | Bug{ | ||
| 1449 | what = [[recursive coroutines may overflow C stack]], | ||
| 1450 | report = [[ , on ]], | ||
| 1451 | since = [[5.0]], | ||
| 1452 | example = [[ | ||
| 1453 | a = function(a) coroutine.wrap(a)(a) end | ||
| 1454 | a(a) | ||
| 1455 | ]], | ||
| 1456 | patch = [[The 'nCcalls' counter should be shared by all threads. | ||
| 1457 | (That is, it should be declared in the 'global_State' structure, | ||
| 1458 | not in 'lua_State'.) | ||
| 1459 | ]], | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | Bug{ | ||
| 1463 | what = [[wrong error message in some concatenations]], | ||
| 1464 | report = [[Alex Davies, on 05/2007]], | ||
| 1465 | since = [[5.1.2]], | ||
| 1466 | example = [[a = nil; a = (1)..a]], | ||
| 1467 | patch = [[ | ||
| 1468 | ldebug.c: | ||
| 1469 | @@ -563,8 +563,8 @@ | ||
| 1470 | |||
| 1471 | |||
| 1472 | void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { | ||
| 1473 | - if (ttisstring(p1)) p1 = p2; | ||
| 1474 | - lua_assert(!ttisstring(p1)); | ||
| 1475 | + if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; | ||
| 1476 | + lua_assert(!ttisstring(p1) && !ttisnumber(p1)); | ||
| 1477 | luaG_typeerror(L, p1, "concatenate"); | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | ]], | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | Bug{ | ||
| 1484 | what = [[Very small numbers all collide in the hash function. | ||
| 1485 | (This creates only performance problems; the behavoir is correct.)]], | ||
| 1486 | report = [[, on ]], | ||
| 1487 | since = [[5.0]], | ||
| 1488 | example = [[]], | ||
| 1489 | patch = [[ | ||
| 1490 | ltable.c: | ||
| 1491 | 87,88c87,88 | ||
| 1492 | < n += 1; /* normalize number (avoid -0) */ | ||
| 1493 | < lua_assert(sizeof(a) <= sizeof(n)); | ||
| 1494 | --- | ||
| 1495 | > if (luai_numeq(n, 0)) /* avoid problems with -0 */ | ||
| 1496 | > return gnode(t, 0); | ||
| 1497 | ]], | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | Bug{ | ||
| 1501 | what = [[Too many variables in an assignment may cause a | ||
| 1502 | C stack overflow]], | ||
| 1503 | report = [[Mike Pall, on 07/2007]], | ||
| 1504 | since = [[5.0]], | ||
| 1505 | example = [[ | ||
| 1506 | $ ulimit -s 1024 # Reduce C stack to 1MB for quicker results | ||
| 1507 | $ lua -e 'local s = "a,"; for i=1,18 do s = s..s end print(loadstring("local a;"..s.."a=nil", ""))' | ||
| 1508 | ]], | ||
| 1509 | patch = [[ | ||
| 1510 | lparser.c: | ||
| 1511 | @@ -938,6 +938,8 @@ | ||
| 1512 | primaryexp(ls, &nv.v); | ||
| 1513 | if (nv.v.k == VLOCAL) | ||
| 1514 | check_conflict(ls, lh, &nv.v); | ||
| 1515 | + luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls, | ||
| 1516 | + "variable names"); | ||
| 1517 | assignment(ls, &nv, nvars+1); | ||
| 1518 | } | ||
| 1519 | else { /* assignment -> `=' explist1 */ | ||
| 1520 | ]], | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | Bug{ | ||
| 1524 | what = [[An error in a module loaded through the '-l' option | ||
| 1525 | shows no traceback]], | ||
| 1526 | report = [[David Manura, on 08/2007]], | ||
| 1527 | since = [[5.1]], | ||
| 1528 | example = [[lua -ltemp (assuming temp.lua has an error)]], | ||
| 1529 | patch = [[ | ||
| 1530 | lua.c: | ||
| 1531 | @@ -144,7 +144,7 @@ | ||
| 1532 | static int dolibrary (lua_State *L, const char *name) { | ||
| 1533 | lua_getglobal(L, "require"); | ||
| 1534 | lua_pushstring(L, name); | ||
| 1535 | - return report(L, lua_pcall(L, 1, 0, 0)); | ||
| 1536 | + return report(L, docall(L, 1, 1)); | ||
| 1537 | } | ||
| 1538 | ]], | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | Bug{ | ||
| 1542 | what = [['gsub' may go wild when wrongly called without its third | ||
| 1543 | argument and with a large subject]], | ||
| 1544 | report = [[Florian Berger, on 10/2007]], | ||
| 1545 | since = [[5.1]], | ||
| 1546 | example = [[ | ||
| 1547 | x = string.rep('a', 10000) .. string.rep('b', 10000) | ||
| 1548 | print(#string.gsub(x, 'b')) | ||
| 1549 | ]], | ||
| 1550 | patch = [[ | ||
| 1551 | lstrlib.c: | ||
| 1552 | @@ -631,6 +631,2 @@ | ||
| 1553 | } | ||
| 1554 | - default: { | ||
| 1555 | - luaL_argerror(L, 3, "string/function/table expected"); | ||
| 1556 | - return; | ||
| 1557 | - } | ||
| 1558 | } | ||
| 1559 | @@ -650,2 +646,3 @@ | ||
| 1560 | const char *p = luaL_checkstring(L, 2); | ||
| 1561 | + int tr = lua_type(L, 3); | ||
| 1562 | int max_s = luaL_optint(L, 4, srcl+1); | ||
| 1563 | @@ -655,2 +652,5 @@ | ||
| 1564 | luaL_Buffer b; | ||
| 1565 | + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || | ||
| 1566 | + tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, | ||
| 1567 | + "string/function/table expected"); | ||
| 1568 | luaL_buffinit(L, &b); | ||
| 1569 | ]], | ||
| 1570 | } | ||
| 1571 | |||
| 1572 | Bug{ | ||
| 1573 | what = [[table.remove removes last element of a table when given | ||
| 1574 | an out-of-bound index]], | ||
| 1575 | report = [[Patrick Donnelly, on 11/2007]], | ||
| 1576 | since = [[5.0]], | ||
| 1577 | example = [[ | ||
| 1578 | a = {1,2,3} | ||
| 1579 | table.remove(a, 4) | ||
| 1580 | print(a[3]) --> nil (should be 3) | ||
| 1581 | ]], | ||
| 1582 | patch = [[ | ||
| 1583 | ltablib.c: | ||
| 1584 | @@ -118,7 +118,8 @@ | ||
| 1585 | static int tremove (lua_State *L) { | ||
| 1586 | int e = aux_getn(L, 1); | ||
| 1587 | int pos = luaL_optint(L, 2, e); | ||
| 1588 | - if (e == 0) return 0; /* table is `empty' */ | ||
| 1589 | + if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ | ||
| 1590 | + return 0; /* nothing to remove */ | ||
| 1591 | luaL_setn(L, 1, e - 1); /* t.n = n-1 */ | ||
| 1592 | lua_rawgeti(L, 1, pos); /* result = t[pos] */ | ||
| 1593 | for ( ;pos<e; pos++) { | ||
| 1594 | ]], | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | Bug{ | ||
| 1598 | what = [[lua_setfenv may crash if called over an invalid object]], | ||
| 1599 | report = [[Mike Pall, on 11/2007]], | ||
| 1600 | since = [[5.1]], | ||
| 1601 | example = [[ | ||
| 1602 | > debug.setfenv(3, {}) | ||
| 1603 | ]], | ||
| 1604 | patch = [[ | ||
| 1605 | lapi.c: | ||
| 1606 | @@ -749,7 +749,7 @@ | ||
| 1607 | res = 0; | ||
| 1608 | break; | ||
| 1609 | } | ||
| 1610 | - luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); | ||
| 1611 | + if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); | ||
| 1612 | L->top--; | ||
| 1613 | lua_unlock(L); | ||
| 1614 | return res; | ||
| 1615 | ]], | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | Bug{ | ||
| 1619 | what = [[stand-alone interpreter shows incorrect error message | ||
| 1620 | when the "message" is a coroutine]], | ||
| 1621 | report = [[Patrick Donnelly, on 17/12/2007]], | ||
| 1622 | since = [[5.1]], | ||
| 1623 | example = [[> error(coroutine.create(function() end))]], | ||
| 1624 | patch = [[ | ||
| 1625 | lua.c: | ||
| 1626 | @@ -74,6 +74,8 @@ | ||
| 1627 | |||
| 1628 | |||
| 1629 | static int traceback (lua_State *L) { | ||
| 1630 | + if (!lua_isstring(L, 1)) /* 'message' not a string? */ | ||
| 1631 | + return 1; /* keep it intact */ | ||
| 1632 | lua_getfield(L, LUA_GLOBALSINDEX, "debug"); | ||
| 1633 | if (!lua_istable(L, -1)) { | ||
| 1634 | lua_pop(L, 1); | ||
| 1635 | |||
| 1636 | ]], | ||
| 1637 | } | ||
| 1638 | |||
| 1639 | Bug{ | ||
| 1640 | what = [[debug.sethook/gethook may overflow the thread's stack]], | ||
| 1641 | report = [[Ivko Stanilov, on 2008/01/04]], | ||
| 1642 | since = [[5.1]], | ||
| 1643 | example = [[ | ||
| 1644 | a = coroutine.create(function() yield() end) | ||
| 1645 | coroutine.resume(a) | ||
| 1646 | debug.sethook(a) -- may overflow the stack of 'a' | ||
| 1647 | ]], | ||
| 1648 | patch = [[ | ||
| 1649 | ldblib.c: | ||
| 1650 | @@ -268,12 +268,11 @@ | ||
| 1651 | count = luaL_optint(L, arg+3, 0); | ||
| 1652 | func = hookf; mask = makemask(smask, count); | ||
| 1653 | } | ||
| 1654 | - gethooktable(L1); | ||
| 1655 | - lua_pushlightuserdata(L1, L1); | ||
| 1656 | + gethooktable(L); | ||
| 1657 | + lua_pushlightuserdata(L, L1); | ||
| 1658 | lua_pushvalue(L, arg+1); | ||
| 1659 | - lua_xmove(L, L1, 1); | ||
| 1660 | - lua_rawset(L1, -3); /* set new hook */ | ||
| 1661 | - lua_pop(L1, 1); /* remove hook table */ | ||
| 1662 | + lua_rawset(L, -3); /* set new hook */ | ||
| 1663 | + lua_pop(L, 1); /* remove hook table */ | ||
| 1664 | lua_sethook(L1, func, mask, count); /* set hooks */ | ||
| 1665 | return 0; | ||
| 1666 | } | ||
| 1667 | @@ -288,11 +287,10 @@ | ||
| 1668 | if (hook != NULL && hook != hookf) /* external hook? */ | ||
| 1669 | lua_pushliteral(L, "external hook"); | ||
| 1670 | else { | ||
| 1671 | - gethooktable(L1); | ||
| 1672 | - lua_pushlightuserdata(L1, L1); | ||
| 1673 | - lua_rawget(L1, -2); /* get hook */ | ||
| 1674 | - lua_remove(L1, -2); /* remove hook table */ | ||
| 1675 | - lua_xmove(L1, L, 1); | ||
| 1676 | + gethooktable(L); | ||
| 1677 | + lua_pushlightuserdata(L, L1); | ||
| 1678 | + lua_rawget(L, -2); /* get hook */ | ||
| 1679 | + lua_remove(L, -2); /* remove hook table */ | ||
| 1680 | } | ||
| 1681 | lua_pushstring(L, unmakemask(mask, buff)); | ||
| 1682 | lua_pushinteger(L, lua_gethookcount(L1)); | ||
| 1683 | ]] | ||
| 1684 | } | ||
| 1685 | |||
| 1686 | |||
| 1687 | |||
| 1688 | ----------------------------------------------------------------- | ||
| 1689 | -- Lua 5.1.3 | ||
| 1690 | |||
| 1691 | Bug{ | ||
| 1692 | what = [[LUAI_MAXCSTACK must be smaller than -LUA_REGISTRYINDEX]], | ||
| 1693 | report = [[Patrick Donnelly, on 2008/02/11]], | ||
| 1694 | since = [[5.1.3]], | ||
| 1695 | example = [[ | ||
| 1696 | j = 1e4 | ||
| 1697 | co = coroutine.create(function() | ||
| 1698 | t = {} | ||
| 1699 | for i = 1, j do t[i] = i end | ||
| 1700 | return unpack(t) | ||
| 1701 | end) | ||
| 1702 | print(coroutine.resume(co)) | ||
| 1703 | ]], | ||
| 1704 | patch = [[ | ||
| 1705 | luaconf.h: | ||
| 1706 | 443c443,444 | ||
| 1707 | < ** functions to consume unlimited stack space. | ||
| 1708 | --- | ||
| 1709 | > ** functions to consume unlimited stack space. (must be smaller than | ||
| 1710 | > ** -LUA_REGISTRYINDEX) | ||
| 1711 | 445,446c446 | ||
| 1712 | < #define LUAI_MCS_AUX ((int)(INT_MAX / (4*sizeof(LUA_NUMBER)))) | ||
| 1713 | < #define LUAI_MAXCSTACK (LUAI_MCS_AUX > SHRT_MAX ? SHRT_MAX : LUAI_MCS_AUX) | ||
| 1714 | --- | ||
| 1715 | > #define LUAI_MAXCSTACK 8000 | ||
| 1716 | ]], | ||
| 1717 | } | ||
| 1718 | |||
| 1719 | Bug{ | ||
| 1720 | what = [[coroutine.resume pushes element without ensuring stack size]], | ||
| 1721 | report = [[on 2008/02/11]], | ||
| 1722 | since = [[5.0]], | ||
| 1723 | example = [[(this bug cannot be detected without internal assertions)]], | ||
| 1724 | patch = [[ | ||
| 1725 | lbaselib.c: | ||
| 1726 | @@ -526,7 +526,7 @@ | ||
| 1727 | status = lua_resume(co, narg); | ||
| 1728 | if (status == 0 || status == LUA_YIELD) { | ||
| 1729 | int nres = lua_gettop(co); | ||
| 1730 | - if (!lua_checkstack(L, nres)) | ||
| 1731 | + if (!lua_checkstack(L, nres + 1)) | ||
| 1732 | luaL_error(L, "too many results to resume"); | ||
| 1733 | lua_xmove(co, L, nres); /* move yielded values */ | ||
| 1734 | return nres; | ||
| 1735 | ]], | ||
| 1736 | } | ||
| 1737 | |||
| 1738 | Bug{ | ||
| 1739 | what = [[lua_checkstack may have arithmetic overflow for large 'size']], | ||
| 1740 | report = [[Patrick Donnelly, on 2008/02/12]], | ||
| 1741 | since = [[5.0]], | ||
| 1742 | example = [[ | ||
| 1743 | print(unpack({1,2,3}, 0, 2^31-3)) | ||
| 1744 | ]], | ||
| 1745 | patch = [[ | ||
| 1746 | --- lapi.c 2008/01/03 15:20:39 2.55.1.3 | ||
| 1747 | +++ lapi.c 2008/02/14 16:05:21 | ||
| 1748 | @@ -93,15 +93,14 @@ | ||
| 1749 | |||
| 1750 | |||
| 1751 | LUA_API int lua_checkstack (lua_State *L, int size) { | ||
| 1752 | - int res; | ||
| 1753 | + int res = 1; | ||
| 1754 | lua_lock(L); | ||
| 1755 | - if ((L->top - L->base + size) > LUAI_MAXCSTACK) | ||
| 1756 | + if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK) | ||
| 1757 | res = 0; /* stack overflow */ | ||
| 1758 | - else { | ||
| 1759 | + else if (size > 0) { | ||
| 1760 | luaD_checkstack(L, size); | ||
| 1761 | if (L->ci->top < L->top + size) | ||
| 1762 | L->ci->top = L->top + size; | ||
| 1763 | - res = 1; | ||
| 1764 | } | ||
| 1765 | lua_unlock(L); | ||
| 1766 | return res; | ||
| 1767 | ]], | ||
| 1768 | } | ||
| 1769 | |||
| 1770 | Bug{ | ||
| 1771 | what = [[unpack with maximum indices may crash due to arithmetic overflow]], | ||
| 1772 | report = [[Patrick Donnelly, on 2008/02/12]], | ||
| 1773 | since = [[5.1]], | ||
| 1774 | example = [[ | ||
| 1775 | print(unpack({1,2,3}, 2^31-1, 2^31-1)) | ||
| 1776 | ]], | ||
| 1777 | patch = [[ | ||
| 1778 | --- lbaselib.c 2008/02/11 16:24:24 1.191.1.5 | ||
| 1779 | +++ lbaselib.c 2008/02/14 16:10:25 | ||
| 1780 | @@ -344,10 +344,12 @@ | ||
| 1781 | luaL_checktype(L, 1, LUA_TTABLE); | ||
| 1782 | i = luaL_optint(L, 2, 1); | ||
| 1783 | e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1)); | ||
| 1784 | + if (i > e) return 0; /* empty range */ | ||
| 1785 | n = e - i + 1; /* number of elements */ | ||
| 1786 | - if (n <= 0) return 0; /* empty range */ | ||
| 1787 | - luaL_checkstack(L, n, "table too big to unpack"); | ||
| 1788 | - for (; i<=e; i++) /* push arg[i...e] */ | ||
| 1789 | + if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ | ||
| 1790 | + return luaL_error(L, "too many results to unpack"); | ||
| 1791 | + lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ | ||
| 1792 | + while (i++ < e) /* push arg[i + 1...e] */ | ||
| 1793 | lua_rawgeti(L, 1, i); | ||
| 1794 | return n; | ||
| 1795 | } | ||
| 1796 | ]], | ||
| 1797 | } | ||
| 1798 | |||
| 1799 | Bug{ | ||
| 1800 | what = [[The validator for precompiled code has several flaws that | ||
| 1801 | allow malicious binary code to crash the application]], | ||
| 1802 | report = [[Peter Cawley, on 2008/03/24]], | ||
| 1803 | since = [[5.0]], | ||
| 1804 | example = [[ | ||
| 1805 | a = string.dump(function()return;end) | ||
| 1806 | a = a:gsub(string.char(30,37,122,128), string.char(34,0,0), 1) | ||
| 1807 | loadstring(a)() | ||
| 1808 | ]], | ||
| 1809 | patch = [[ | ||
| 1810 | --- ldebug.c 2007/12/28 15:32:23 2.29.1.3 | ||
| 1811 | +++ ldebug.c 2008/04/04 15:15:40 | ||
| 1812 | @@ -275,12 +275,12 @@ | ||
| 1813 | |||
| 1814 | static int precheck (const Proto *pt) { | ||
| 1815 | check(pt->maxstacksize <= MAXSTACK); | ||
| 1816 | - lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); | ||
| 1817 | - lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) || | ||
| 1818 | + check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); | ||
| 1819 | + check(!(pt->is_vararg & VARARG_NEEDSARG) || | ||
| 1820 | (pt->is_vararg & VARARG_HASARG)); | ||
| 1821 | check(pt->sizeupvalues <= pt->nups); | ||
| 1822 | check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); | ||
| 1823 | - check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); | ||
| 1824 | + check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); | ||
| 1825 | return 1; | ||
| 1826 | } | ||
| 1827 | |||
| 1828 | @@ -363,7 +363,11 @@ | ||
| 1829 | } | ||
| 1830 | switch (op) { | ||
| 1831 | case OP_LOADBOOL: { | ||
| 1832 | - check(c == 0 || pc+2 < pt->sizecode); /* check its jump */ | ||
| 1833 | + if (c == 1) { /* does it jump? */ | ||
| 1834 | + check(pc+2 < pt->sizecode); /* check its jump */ | ||
| 1835 | + check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST || | ||
| 1836 | + GETARG_C(pt->code[pc+1]) != 0); | ||
| 1837 | + } | ||
| 1838 | break; | ||
| 1839 | } | ||
| 1840 | case OP_LOADNIL: { | ||
| 1841 | @@ -428,7 +432,10 @@ | ||
| 1842 | } | ||
| 1843 | case OP_SETLIST: { | ||
| 1844 | if (b > 0) checkreg(pt, a + b); | ||
| 1845 | - if (c == 0) pc++; | ||
| 1846 | + if (c == 0) { | ||
| 1847 | + pc++; | ||
| 1848 | + check(pc < pt->sizecode - 1); | ||
| 1849 | + } | ||
| 1850 | break; | ||
| 1851 | } | ||
| 1852 | case OP_CLOSURE: { | ||
| 1853 | ]], | ||
| 1854 | } | ||
| 1855 | |||
| 1856 | Bug{ | ||
| 1857 | what = [[maliciously crafted precompiled code can blow the C stack]], | ||
| 1858 | report = [[Greg Falcon, on 2008/03/25]], | ||
| 1859 | since = [[5.0]], | ||
| 1860 | example = [[ | ||
| 1861 | function crash(depth) | ||
| 1862 | local init = '\27\76\117\97\81\0\1\4\4\4\8\0\7\0\0\0\61\115\116' .. | ||
| 1863 | '\100\105\110\0\1\0\0\0\1\0\0\0\0\0\0\2\2\0\0\0\36' .. | ||
| 1864 | '\0\0\0\30\0\128\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0' .. | ||
| 1865 | '\1\0\0\0\0\0\0\2' | ||
| 1866 | local mid = '\1\0\0\0\30\0\128\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0' | ||
| 1867 | local fin = '\0\0\0\0\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0' .. | ||
| 1868 | '\0\0\97\0\1\0\0\0\1\0\0\0\0\0\0\0' | ||
| 1869 | local lch = '\2\0\0\0\36\0\0\0\30\0\128\0\0\0\0\0\1\0\0\0\0\0\0' .. | ||
| 1870 | '\0\1\0\0\0\1\0\0\0\0\0\0\2' | ||
| 1871 | local rch = '\0\0\0\0\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0' .. | ||
| 1872 | '\0\0\97\0\1\0\0\0\1' | ||
| 1873 | for i=1,depth do lch,rch = lch..lch,rch..rch end | ||
| 1874 | loadstring(init .. lch .. mid .. rch .. fin) | ||
| 1875 | end | ||
| 1876 | for i=1,25 do print(i); crash(i) end | ||
| 1877 | ]], | ||
| 1878 | patch = [[ | ||
| 1879 | --- lundump.c 2008/04/04 16:00:45 2.7.1.3 | ||
| 1880 | +++ lundump.c 2008/04/04 19:51:41 2.7.1.4 | ||
| 1881 | @@ -161,7 +161,9 @@ | ||
| 1882 | |||
| 1883 | static Proto* LoadFunction(LoadState* S, TString* p) | ||
| 1884 | { | ||
| 1885 | - Proto* f=luaF_newproto(S->L); | ||
| 1886 | + Proto* f; | ||
| 1887 | + if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code too deep"); | ||
| 1888 | + f=luaF_newproto(S->L); | ||
| 1889 | setptvalue2s(S->L,S->L->top,f); incr_top(S->L); | ||
| 1890 | f->source=LoadString(S); if (f->source==NULL) f->source=p; | ||
| 1891 | f->linedefined=LoadInt(S); | ||
| 1892 | @@ -175,6 +177,7 @@ | ||
| 1893 | LoadDebug(S,f); | ||
| 1894 | IF (!luaG_checkcode(f), "bad code"); | ||
| 1895 | S->L->top--; | ||
| 1896 | + S->L->nCcalls--; | ||
| 1897 | return f; | ||
| 1898 | } | ||
| 1899 | ]], | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | Bug{ | ||
| 1903 | what = [[code validator may reject (maliciously crafted) correct code]], | ||
| 1904 | report = [[Greg Falcon, on 2008/03/26]], | ||
| 1905 | since = [[5.0]], | ||
| 1906 | example = [[ | ||
| 1907 | z={} | ||
| 1908 | for i=1,27290 do z[i]='1,' end | ||
| 1909 | z = 'if 1+1==2 then local a={' .. table.concat(z) .. '} end' | ||
| 1910 | func = loadstring(z) | ||
| 1911 | print(loadstring(string.dump(func))) | ||
| 1912 | ]], | ||
| 1913 | patch = [[ | ||
| 1914 | --- ldebug.c 2008/04/04 15:30:05 2.29.1.4 | ||
| 1915 | +++ ldebug.c 2008/04/04 15:47:10 | ||
| 1916 | @@ -346,9 +346,18 @@ | ||
| 1917 | int dest = pc+1+b; | ||
| 1918 | check(0 <= dest && dest < pt->sizecode); | ||
| 1919 | if (dest > 0) { | ||
| 1920 | - /* cannot jump to a setlist count */ | ||
| 1921 | - Instruction d = pt->code[dest-1]; | ||
| 1922 | - check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); | ||
| 1923 | + int j; | ||
| 1924 | + /* check that it does not jump to a setlist count; this | ||
| 1925 | + is tricky, because the count from a previous setlist may | ||
| 1926 | + have the same value of an invalid setlist; so, we must | ||
| 1927 | + go all the way back to the first of them (if any) */ | ||
| 1928 | + for (j = 0; j < dest; j++) { | ||
| 1929 | + Instruction d = pt->code[dest-1-j]; | ||
| 1930 | + if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break; | ||
| 1931 | + } | ||
| 1932 | + /* if 'j' is even, previous value is not a setlist (even if | ||
| 1933 | + it looks like one) */ | ||
| 1934 | + check((j&1) == 0); | ||
| 1935 | } | ||
| 1936 | } | ||
| 1937 | break; | ||
| 1938 | ]], | ||
| 1939 | } | ||
| 1940 | |||
| 1941 | Bug{ | ||
| 1942 | what = [[maliciously crafted precompiled code can inject invalid boolean | ||
| 1943 | values into Lua code]], | ||
| 1944 | report = [[Greg Falcon, on 2008/03/27]], | ||
| 1945 | since = [[5.0]], | ||
| 1946 | example = [[ | ||
| 1947 | maybe = string.dump(function() return ({[true]=true})[true] end) | ||
| 1948 | maybe = maybe:gsub('\1\1','\1\2') | ||
| 1949 | maybe = loadstring(maybe)() | ||
| 1950 | assert(type(maybe) == "boolean" and maybe ~= true and maybe ~= false) | ||
| 1951 | ]], | ||
| 1952 | patch = [[ | ||
| 1953 | --- lundump.c 2008/01/18 16:39:11 2.7.1.2 | ||
| 1954 | +++ lundump.c 2008/04/04 15:50:39 | ||
| 1955 | @@ -115,7 +115,7 @@ | ||
| 1956 | setnilvalue(o); | ||
| 1957 | break; | ||
| 1958 | case LUA_TBOOLEAN: | ||
| 1959 | - setbvalue(o,LoadChar(S)); | ||
| 1960 | + setbvalue(o,LoadChar(S)!=0); | ||
| 1961 | break; | ||
| 1962 | case LUA_TNUMBER: | ||
| 1963 | setnvalue(o,LoadNumber(S)); | ||
| 1964 | ]], | ||
| 1965 | } | ||
| 1966 | |||
| 1967 | |||
| 1968 | Bug{ | ||
| 1969 | what = [['string.byte' gets confused with some out-of-range negative indices]], | ||
| 1970 | report = [[Mike Pall, on 2008/06/03]], | ||
| 1971 | since = [[5.1]], | ||
| 1972 | example = [[ | ||
| 1973 | print(string.byte("abc", -5)) --> 97 98 99 (should print nothing) | ||
| 1974 | ]], | ||
| 1975 | patch = [[ | ||
| 1976 | --- lstrlib.c 2007/12/28 15:32:23 1.132.1.3 | ||
| 1977 | +++ lstrlib.c 2008/07/05 11:53:42 | ||
| 1978 | @@ -35,7 +35,8 @@ | ||
| 1979 | |||
| 1980 | static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) { | ||
| 1981 | /* relative string position: negative means back from end */ | ||
| 1982 | - return (pos>=0) ? pos : (ptrdiff_t)len+pos+1; | ||
| 1983 | + if (pos < 0) pos += (ptrdiff_t)len + 1; | ||
| 1984 | + return (pos >= 0) ? pos : 0; | ||
| 1985 | } | ||
| 1986 | |||
| 1987 | |||
| 1988 | ]], | ||
| 1989 | } | ||
| 1990 | |||
| 1991 | |||
| 1992 | Bug{ | ||
| 1993 | what = [[user-requested GC step may loop forever]], | ||
| 1994 | report = [[Makoto Hamanaka, on 2008/07/01]], | ||
| 1995 | since = [[5.1]], | ||
| 1996 | example = [[ | ||
| 1997 | collectgarbage("setpause", 100) -- small value | ||
| 1998 | collectgarbage("setstepmul", 2000) -- large value | ||
| 1999 | collectgarbage("step",0) | ||
| 2000 | ]], | ||
| 2001 | patch = [[ | ||
| 2002 | --- lapi.c 2008/02/14 16:46:39 2.55.1.4 | ||
| 2003 | +++ lapi.c 2008/07/04 18:34:48 | ||
| 2004 | @@ -929,10 +929,13 @@ | ||
| 2005 | g->GCthreshold = g->totalbytes - a; | ||
| 2006 | else | ||
| 2007 | g->GCthreshold = 0; | ||
| 2008 | - while (g->GCthreshold <= g->totalbytes) | ||
| 2009 | + while (g->GCthreshold <= g->totalbytes) { | ||
| 2010 | luaC_step(L); | ||
| 2011 | - if (g->gcstate == GCSpause) /* end of cycle? */ | ||
| 2012 | - res = 1; /* signal it */ | ||
| 2013 | + if (g->gcstate == GCSpause) { /* end of cycle? */ | ||
| 2014 | + res = 1; /* signal it */ | ||
| 2015 | + break; | ||
| 2016 | + } | ||
| 2017 | + } | ||
| 2018 | break; | ||
| 2019 | } | ||
| 2020 | case LUA_GCSETPAUSE: { | ||
| 2021 | ]], | ||
| 2022 | } | ||
| 2023 | |||
| 2024 | |||
| 2025 | Bug{ | ||
| 2026 | what = [['module' may change the environment of a C function]], | ||
| 2027 | report = [[Peter Cawley, on 2008/07/16]], | ||
| 2028 | since = [[5.1]], | ||
| 2029 | example = [[ | ||
| 2030 | pcall(module, "xuxu") | ||
| 2031 | assert(debug.getfenv(pcall) == xuxu) | ||
| 2032 | ]], | ||
| 2033 | patch = [[ | ||
| 2034 | --- loadlib.c 2007/12/28 14:58:43 1.52.1.2 | ||
| 2035 | +++ loadlib.c 2008/08/05 19:39:00 | ||
| 2036 | @@ -506,8 +506,11 @@ | ||
| 2037 | |||
| 2038 | static void setfenv (lua_State *L) { | ||
| 2039 | lua_Debug ar; | ||
| 2040 | - lua_getstack(L, 1, &ar); | ||
| 2041 | - lua_getinfo(L, "f", &ar); | ||
| 2042 | + if (lua_getstack(L, 1, &ar) == 0 || | ||
| 2043 | + lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ | ||
| 2044 | + lua_iscfunction(L, -1)) | ||
| 2045 | + luaL_error(L, "function " LUA_QL("module") | ||
| 2046 | + " not called from a Lua function"); | ||
| 2047 | lua_pushvalue(L, -2); | ||
| 2048 | lua_setfenv(L, -2); | ||
| 2049 | lua_pop(L, 1); | ||
| 2050 | ]], | ||
| 2051 | } | ||
| 2052 | |||
| 2053 | |||
| 2054 | Bug{ | ||
| 2055 | what = [[internal macro 'svalue' is wrong]], | ||
| 2056 | report = [[Martijn van Buul, on 2008/08/04]], | ||
| 2057 | since = [[5.1]], | ||
| 2058 | example = [[ | ||
| 2059 | /* in luaconf.h */ | ||
| 2060 | #define LUAI_USER_ALIGNMENT_T union { char b[32]; } | ||
| 2061 | ]], | ||
| 2062 | patch = [[ | ||
| 2063 | --- lobject.h 2007/12/27 13:02:25 2.20.1.1 | ||
| 2064 | +++ lobject.h 2008/08/05 19:40:48 | ||
| 2065 | @@ -210,3 +210,3 @@ | ||
| 2066 | #define getstr(ts) cast(const char *, (ts) + 1) | ||
| 2067 | -#define svalue(o) getstr(tsvalue(o)) | ||
| 2068 | +#define svalue(o) getstr(rawtsvalue(o)) | ||
| 2069 | |||
| 2070 | ]], | ||
| 2071 | } | ||
| 2072 | |||
| 2073 | |||
| 2074 | ----------------------------------------------------------------- | ||
| 2075 | -- Lua 5.1.4 | ||
| 2076 | |||
| 2077 | Bug{ | ||
| 2078 | what = [[malicious zero-length string in binary code may segfault Lua]], | ||
| 2079 | report = [[Peter Cawley, on 2008/09/01]], | ||
| 2080 | since = [[5.1]], | ||
| 2081 | example = [[ | ||
| 2082 | loadstring(('').dump(function()X''end):gsub('\2%z%z%zX','\0\0\0'))() | ||
| 2083 | ]], | ||
| 2084 | patch = [[ | ||
| 2085 | ]], | ||
| 2086 | } | ||
| 2087 | |||
| 2088 | |||
| 2089 | Bug{ | ||
| 2090 | what = [[wrong code generation for some particular boolean expressions]], | ||
| 2091 | report = [[Brian Kelley, on 2009/04/15]], | ||
| 2092 | since = [[5.0]], | ||
| 2093 | example = [[ | ||
| 2094 | print(((1 or false) and true) or false) --> 1 | ||
| 2095 | -- should be 'true' | ||
| 2096 | ]], | ||
| 2097 | patch = [[ | ||
| 2098 | --- lcode.c 2007/12/28 15:32:23 2.25.1.3 | ||
| 2099 | +++ lcode.c 2009/06/15 14:07:34 | ||
| 2100 | @@ -544,15 +544,18 @@ | ||
| 2101 | pc = NO_JUMP; /* always true; do nothing */ | ||
| 2102 | break; | ||
| 2103 | } | ||
| 2104 | - case VFALSE: { | ||
| 2105 | - pc = luaK_jump(fs); /* always jump */ | ||
| 2106 | - break; | ||
| 2107 | - } | ||
| 2108 | case VJMP: { | ||
| 2109 | invertjump(fs, e); | ||
| 2110 | pc = e->u.s.info; | ||
| 2111 | break; | ||
| 2112 | } | ||
| 2113 | + case VFALSE: { | ||
| 2114 | + if (!hasjumps(e)) { | ||
| 2115 | + pc = luaK_jump(fs); /* always jump */ | ||
| 2116 | + break; | ||
| 2117 | + } | ||
| 2118 | + /* else go through */ | ||
| 2119 | + } | ||
| 2120 | default: { | ||
| 2121 | pc = jumponcond(fs, e, 0); | ||
| 2122 | break; | ||
| 2123 | @@ -572,14 +575,17 @@ | ||
| 2124 | pc = NO_JUMP; /* always false; do nothing */ | ||
| 2125 | break; | ||
| 2126 | } | ||
| 2127 | - case VTRUE: { | ||
| 2128 | - pc = luaK_jump(fs); /* always jump */ | ||
| 2129 | - break; | ||
| 2130 | - } | ||
| 2131 | case VJMP: { | ||
| 2132 | pc = e->u.s.info; | ||
| 2133 | break; | ||
| 2134 | } | ||
| 2135 | + case VTRUE: { | ||
| 2136 | + if (!hasjumps(e)) { | ||
| 2137 | + pc = luaK_jump(fs); /* always jump */ | ||
| 2138 | + break; | ||
| 2139 | + } | ||
| 2140 | + /* else go through */ | ||
| 2141 | + } | ||
| 2142 | default: { | ||
| 2143 | pc = jumponcond(fs, e, 1); | ||
| 2144 | break; | ||
| 2145 | ]], | ||
| 2146 | } | ||
| 2147 | |||
| 2148 | Bug{ | ||
| 2149 | what = [['luaV_settable' may invalidate a reference to a table and try | ||
| 2150 | to reuse it]], | ||
| 2151 | report = [[Mark Feldman, on 2009/06/27]], | ||
| 2152 | since = [[5.0]], | ||
| 2153 | example = [[ | ||
| 2154 | grandparent = {} | ||
| 2155 | grandparent.__newindex = function(s,_,_) print(s) end | ||
| 2156 | |||
| 2157 | parent = {} | ||
| 2158 | parent.__newindex = parent | ||
| 2159 | setmetatable(parent, grandparent) | ||
| 2160 | |||
| 2161 | child = setmetatable({}, parent) | ||
| 2162 | child.foo = 10 --> (crash on some machines) | ||
| 2163 | ]], | ||
| 2164 | patch = [[ | ||
| 2165 | --- lvm.c 2007/12/28 15:32:23 2.63.1.3 | ||
| 2166 | +++ lvm.c 2009/07/01 20:36:59 | ||
| 2167 | @@ -133,6 +133,7 @@ | ||
| 2168 | |||
| 2169 | void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { | ||
| 2170 | int loop; | ||
| 2171 | + TValue temp; | ||
| 2172 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | ||
| 2173 | const TValue *tm; | ||
| 2174 | if (ttistable(t)) { /* `t' is a table? */ | ||
| 2175 | @@ -152,7 +153,9 @@ | ||
| 2176 | callTM(L, tm, t, key, val); | ||
| 2177 | return; | ||
| 2178 | } | ||
| 2179 | - t = tm; /* else repeat with `tm' */ | ||
| 2180 | + /* else repeat with `tm' */ | ||
| 2181 | + setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ | ||
| 2182 | + t = &temp; | ||
| 2183 | } | ||
| 2184 | luaG_runerror(L, "loop in settable"); | ||
| 2185 | } | ||
| 2186 | ]], | ||
| 2187 | } | ||
| 2188 | |||
| 2189 | Bug{ | ||
| 2190 | what = [[smart use of varargs may create functions that return too | ||
| 2191 | many arguments and overflow the stack of C functions]], | ||
| 2192 | report = [[Patrick Donnelly, on 2008/12/10]], | ||
| 2193 | since = [[]], | ||
| 2194 | example = [[ | ||
| 2195 | local function lunpack(i, ...) | ||
| 2196 | if i == 0 then return ... | ||
| 2197 | else | ||
| 2198 | return lunpack(i-1, 1, ...) | ||
| 2199 | end | ||
| 2200 | end | ||
| 2201 | |||
| 2202 | Now, if C calls lunpack(n) with a huge n, it may end with | ||
| 2203 | too many values in its stack and confuse its stack indices. | ||
| 2204 | ]], | ||
| 2205 | patch = [[ | ||
| 2206 | ]], | ||
| 2207 | } | ||
| 2208 | |||
| 2209 | Bug{ | ||
| 2210 | what = [['debug.getfenv' does not check whether it has an argument]], | ||
| 2211 | report = [[Patrick Donnelly, 2009/07/30]], | ||
| 2212 | since = [[5.1]], | ||
| 2213 | example = [[debug.getfenv() -- should raise an error]], | ||
| 2214 | patch = [[ | ||
| 2215 | --- ldblib.c 2008/01/21 13:11:21 1.104.1.3 | ||
| 2216 | +++ ldblib.c 2009/08/04 18:43:12 | ||
| 2217 | @@ -45,6 +45,7 @@ | ||
| 2218 | |||
| 2219 | |||
| 2220 | static int db_getfenv (lua_State *L) { | ||
| 2221 | + luaL_checkany(L, 1); | ||
| 2222 | lua_getfenv(L, 1); | ||
| 2223 | return 1; | ||
| 2224 | } | ||
| 2225 | ]], | ||
| 2226 | } | ||
| 2227 | |||
| 2228 | Bug{ | ||
| 2229 | what = [[GC may get stuck during a parser and avoids proper resizing of | ||
| 2230 | the string table, | ||
| 2231 | making its lists grow too much and degrading performance]], | ||
| 2232 | report = [[Sean Conner, 2009/11/10]], | ||
| 2233 | since = [[5.1]], | ||
| 2234 | example = [[See http://lua-users.org/lists/lua-l/2009-11/msg00463.html]], | ||
| 2235 | patch = [[ | ||
| 2236 | --- llex.c 2007/12/27 13:02:25 2.20.1.1 | ||
| 2237 | +++ llex.c 2009/11/23 14:49:40 | ||
| 2238 | @@ -118,8 +118,10 @@ | ||
| 2239 | lua_State *L = ls->L; | ||
| 2240 | TString *ts = luaS_newlstr(L, str, l); | ||
| 2241 | TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ | ||
| 2242 | - if (ttisnil(o)) | ||
| 2243 | + if (ttisnil(o)) { | ||
| 2244 | setbvalue(o, 1); /* make sure `str' will not be collected */ | ||
| 2245 | + luaC_checkGC(L); | ||
| 2246 | + } | ||
| 2247 | return ts; | ||
| 2248 | } | ||
| 2249 | |||
| 2250 | ]] | ||
| 2251 | } | ||
| 2252 | |||
| 2253 | Bug{ | ||
| 2254 | what = [['string.format' may get buffer as an argument when there are | ||
| 2255 | missing arguments and format string is too long]], | ||
| 2256 | report = [[Roberto I., 2010/04/12]], | ||
| 2257 | since = [[5.0]], | ||
| 2258 | example = [[ | ||
| 2259 | x = string.rep("x", 10000) .. "%d" | ||
| 2260 | print(string.format(x)) -- gives wrong error message | ||
| 2261 | ]], | ||
| 2262 | patch = [[ | ||
| 2263 | --- lstrlib.c 2008/07/11 17:27:21 1.132.1.4 | ||
| 2264 | +++ lstrlib.c 2010/05/14 15:12:53 | ||
| 2265 | @@ -754,6 +754,7 @@ | ||
| 2266 | |||
| 2267 | |||
| 2268 | static int str_format (lua_State *L) { | ||
| 2269 | + int top = lua_gettop(L); | ||
| 2270 | int arg = 1; | ||
| 2271 | size_t sfl; | ||
| 2272 | const char *strfrmt = luaL_checklstring(L, arg, &sfl); | ||
| 2273 | @@ -768,7 +769,8 @@ | ||
| 2274 | else { /* format item */ | ||
| 2275 | char form[MAX_FORMAT]; /* to store the format (`%...') */ | ||
| 2276 | char buff[MAX_ITEM]; /* to store the formatted item */ | ||
| 2277 | - arg++; | ||
| 2278 | + if (++arg > top) | ||
| 2279 | + luaL_argerror(L, arg, "no value"); | ||
| 2280 | strfrmt = scanformat(L, strfrmt, form); | ||
| 2281 | switch (*strfrmt++) { | ||
| 2282 | case 'c': { | ||
| 2283 | ]] | ||
| 2284 | } | ||
| 2285 | |||
| 2286 | Bug{ | ||
| 2287 | what = [['io.read(op, "*n")' may return garbage if second read fails]], | ||
| 2288 | report = [[Roberto I., 2010/04/12]], | ||
| 2289 | since = [[5.0]], | ||
| 2290 | example = [[ | ||
| 2291 | print(io.read("*n", "*n")) --<< enter "10 hi" | ||
| 2292 | --> file (0x884420) nil | ||
| 2293 | ]], | ||
| 2294 | patch = [[ | ||
| 2295 | --- liolib.c 2008/01/18 17:47:43 2.73.1.3 | ||
| 2296 | +++ liolib.c 2010/05/14 15:29:29 | ||
| 2297 | @@ -276,7 +276,10 @@ | ||
| 2298 | lua_pushnumber(L, d); | ||
| 2299 | return 1; | ||
| 2300 | } | ||
| 2301 | - else return 0; /* read fails */ | ||
| 2302 | + else { | ||
| 2303 | + lua_pushnil(L); /* "result" to be removed */ | ||
| 2304 | + return 0; /* read fails */ | ||
| 2305 | + } | ||
| 2306 | } | ||
| 2307 | |||
| 2308 | |||
| 2309 | ]] | ||
| 2310 | } | ||
| 2311 | |||
| 2312 | Bug{ | ||
| 2313 | what = [[wrong code generation for some particular boolean expressions]], | ||
| 2314 | report = [[Thierry Van Elsuwe, 2011/01/20]], | ||
| 2315 | since = [[5.0]], | ||
| 2316 | example = [[ | ||
| 2317 | print((('hi' or true) and true) or true) | ||
| 2318 | --> hi (should be true) | ||
| 2319 | print(((nil and nil) or false) and true) | ||
| 2320 | --> nil (should be false) | ||
| 2321 | ]], | ||
| 2322 | patch = [[ | ||
| 2323 | --- lcode.c 2009/06/15 14:12:25 2.25.1.4 | ||
| 2324 | +++ lcode.c 2011/01/31 14:44:25 | ||
| 2325 | @@ -549,13 +549,6 @@ | ||
| 2326 | pc = e->u.s.info; | ||
| 2327 | break; | ||
| 2328 | } | ||
| 2329 | - case VFALSE: { | ||
| 2330 | - if (!hasjumps(e)) { | ||
| 2331 | - pc = luaK_jump(fs); /* always jump */ | ||
| 2332 | - break; | ||
| 2333 | - } | ||
| 2334 | - /* else go through */ | ||
| 2335 | - } | ||
| 2336 | default: { | ||
| 2337 | pc = jumponcond(fs, e, 0); | ||
| 2338 | break; | ||
| 2339 | @@ -579,13 +572,6 @@ | ||
| 2340 | pc = e->u.s.info; | ||
| 2341 | break; | ||
| 2342 | } | ||
| 2343 | - case VTRUE: { | ||
| 2344 | - if (!hasjumps(e)) { | ||
| 2345 | - pc = luaK_jump(fs); /* always jump */ | ||
| 2346 | - break; | ||
| 2347 | - } | ||
| 2348 | - /* else go through */ | ||
| 2349 | - } | ||
| 2350 | default: { | ||
| 2351 | pc = jumponcond(fs, e, 1); | ||
| 2352 | break; | ||
| 2353 | ]] | ||
| 2354 | } | ||
| 2355 | |||
| 2356 | Bug{ | ||
| 2357 | what = [[__newindex metamethod may not work if metatable is its own | ||
| 2358 | metatable]], | ||
| 2359 | report = [[Cuero Bugot, 2011/08/09]], | ||
| 2360 | since = [[5.1]], | ||
| 2361 | example = [[ | ||
| 2362 | meta={} | ||
| 2363 | setmetatable(meta, meta) | ||
| 2364 | meta.__newindex = function(t, key, value) print("set") end | ||
| 2365 | o = setmetatable({}, meta) | ||
| 2366 | o.x = 10 -- should print 'set' | ||
| 2367 | ]], | ||
| 2368 | patch = [[ | ||
| 2369 | --- lvm.c 2009/07/01 21:10:33 2.63.1.4 | ||
| 2370 | +++ lvm.c 2011/08/17 20:36:28 | ||
| 2371 | @@ -142,6 +142,7 @@ | ||
| 2372 | if (!ttisnil(oldval) || /* result is no nil? */ | ||
| 2373 | (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ | ||
| 2374 | setobj2t(L, oldval, val); | ||
| 2375 | + h->flags = 0; | ||
| 2376 | luaC_barriert(L, h, val); | ||
| 2377 | return; | ||
| 2378 | } | ||
| 2379 | ]] | ||
| 2380 | } | ||
| 2381 | |||
| 2382 | Bug{ | ||
| 2383 | what = [[parser may collect a prototype while building it]], | ||
| 2384 | report = [[Ingo van Lil, 2011/10/13]], | ||
| 2385 | since = [[5.1.4 (caused by patch 5.1.4-6)]], | ||
| 2386 | example = nil, | ||
| 2387 | patch = [[ | ||
| 2388 | --- lparser.c 2007/12/28 15:32:23 2.42.1.3 | ||
| 2389 | +++ lparser.c 2011/10/17 13:10:43 | ||
| 2390 | @@ -374,9 +374,9 @@ | ||
| 2391 | lua_assert(luaG_checkcode(f)); | ||
| 2392 | lua_assert(fs->bl == NULL); | ||
| 2393 | ls->fs = fs->prev; | ||
| 2394 | - L->top -= 2; /* remove table and prototype from the stack */ | ||
| 2395 | /* last token read was anchored in defunct function; must reanchor it */ | ||
| 2396 | if (fs) anchor_token(ls); | ||
| 2397 | + L->top -= 2; /* remove table and prototype from the stack */ | ||
| 2398 | } | ||
| 2399 | |||
| 2400 | |||
| 2401 | ]] | ||
| 2402 | } | ||
| 2403 | |||
| 2404 | |||
| 2405 | Bug{ | ||
| 2406 | what = [[When loading a file, | ||
| 2407 | Lua may call the reader function again after it returned end of input | ||
| 2408 | ]], | ||
| 2409 | report = [[Chris Howie, 2013/06/05]], | ||
| 2410 | since = [[5.1]], | ||
| 2411 | fix = [[5.2]], | ||
| 2412 | example = [[ | ||
| 2413 | load(function () print("called"); return nil end) | ||
| 2414 | --> called | ||
| 2415 | --> called (should be called only once!) | ||
| 2416 | ]], | ||
| 2417 | patch = [[ | ||
| 2418 | --- lzio.h 2007/12/27 13:02:25 1.21.1.1 | ||
| 2419 | +++ lzio.h 2013/07/04 13:55:59 | ||
| 2420 | @@ -59,6 +59,7 @@ | ||
| 2421 | lua_Reader reader; | ||
| 2422 | void* data; /* additional data */ | ||
| 2423 | lua_State *L; /* Lua state (for reader) */ | ||
| 2424 | + int eoz; /* true if reader has no more data */ | ||
| 2425 | }; | ||
| 2426 | |||
| 2427 | |||
| 2428 | --- lzio.c 2007/12/27 13:02:25 1.31.1.1 | ||
| 2429 | +++ lzio.c 2013/07/04 13:53:06 | ||
| 2430 | @@ -22,10 +22,14 @@ | ||
| 2431 | size_t size; | ||
| 2432 | lua_State *L = z->L; | ||
| 2433 | const char *buff; | ||
| 2434 | + if (z->eoz) return EOZ; | ||
| 2435 | lua_unlock(L); | ||
| 2436 | buff = z->reader(L, z->data, &size); | ||
| 2437 | lua_lock(L); | ||
| 2438 | - if (buff == NULL || size == 0) return EOZ; | ||
| 2439 | + if (buff == NULL || size == 0) { | ||
| 2440 | + z->eoz = 1; /* avoid calling reader function next time */ | ||
| 2441 | + return EOZ; | ||
| 2442 | + } | ||
| 2443 | z->n = size - 1; | ||
| 2444 | z->p = buff; | ||
| 2445 | return char2int(*(z->p++)); | ||
| 2446 | @@ -51,6 +55,7 @@ | ||
| 2447 | z->data = data; | ||
| 2448 | z->n = 0; | ||
| 2449 | z->p = NULL; | ||
| 2450 | + z->eoz = 0; | ||
| 2451 | } | ||
| 2452 | ]] | ||
| 2453 | } | ||
| 2454 | |||
| 2455 | |||
| 2456 | ----------------------------------------------------------------- | ||
| 2457 | -- Lua 5.2.0 | ||
| 2458 | |||
| 2459 | Bug{ | ||
| 2460 | what = [[memory hoarding when creating Lua hooks for coroutines]], | ||
| 2461 | report = [[Arseny Vakhrushev, 2012/01/16]], | ||
| 2462 | since = [[5.1]], | ||
| 2463 | fix = [[5.2.1]], | ||
| 2464 | example = [[ | ||
| 2465 | collectgarbage(); print(collectgarbage'count' * 1024) | ||
| 2466 | |||
| 2467 | for i = 1, 100 do | ||
| 2468 | local co = coroutine.create(function () end) | ||
| 2469 | local x = {} | ||
| 2470 | for j=1,1000 do x[j] = j end | ||
| 2471 | debug.sethook(co, function () return x end, 'l') | ||
| 2472 | end | ||
| 2473 | |||
| 2474 | collectgarbage(); print(collectgarbage'count' * 1024) | ||
| 2475 | -- value should back to near the original level | ||
| 2476 | ]], | ||
| 2477 | patch = [[ | ||
| 2478 | -- For 5.2 | ||
| 2479 | |||
| 2480 | --- ldblib.c 2011/10/24 14:54:05 1.131 | ||
| 2481 | +++ ldblib.c 2012/01/18 02:36:59 | ||
| 2482 | @@ -253,14 +253,15 @@ | ||
| 2483 | } | ||
| 2484 | |||
| 2485 | |||
| 2486 | -#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY); | ||
| 2487 | +#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY) | ||
| 2488 | |||
| 2489 | |||
| 2490 | static void hookf (lua_State *L, lua_Debug *ar) { | ||
| 2491 | static const char *const hooknames[] = | ||
| 2492 | {"call", "return", "line", "count", "tail call"}; | ||
| 2493 | gethooktable(L); | ||
| 2494 | - lua_rawgetp(L, -1, L); | ||
| 2495 | + lua_pushthread(L); | ||
| 2496 | + lua_rawget(L, -2); | ||
| 2497 | if (lua_isfunction(L, -1)) { | ||
| 2498 | lua_pushstring(L, hooknames[(int)ar->event]); | ||
| 2499 | if (ar->currentline >= 0) | ||
| 2500 | @@ -306,10 +307,15 @@ | ||
| 2501 | count = luaL_optint(L, arg+3, 0); | ||
| 2502 | func = hookf; mask = makemask(smask, count); | ||
| 2503 | } | ||
| 2504 | - gethooktable(L); | ||
| 2505 | + if (gethooktable(L) == 0) { /* creating hook table? */ | ||
| 2506 | + lua_pushstring(L, "k"); | ||
| 2507 | + lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ | ||
| 2508 | + lua_pushvalue(L, -1); | ||
| 2509 | + lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ | ||
| 2510 | + } | ||
| 2511 | + lua_pushthread(L1); lua_xmove(L1, L, 1); | ||
| 2512 | lua_pushvalue(L, arg+1); | ||
| 2513 | - lua_rawsetp(L, -2, L1); /* set new hook */ | ||
| 2514 | - lua_pop(L, 1); /* remove hook table */ | ||
| 2515 | + lua_rawset(L, -3); /* set new hook */ | ||
| 2516 | lua_sethook(L1, func, mask, count); /* set hooks */ | ||
| 2517 | return 0; | ||
| 2518 | } | ||
| 2519 | @@ -325,7 +331,8 @@ | ||
| 2520 | lua_pushliteral(L, "external hook"); | ||
| 2521 | else { | ||
| 2522 | gethooktable(L); | ||
| 2523 | - lua_rawgetp(L, -1, L1); /* get hook */ | ||
| 2524 | + lua_pushthread(L1); lua_xmove(L1, L, 1); | ||
| 2525 | + lua_rawget(L, -2); /* get hook */ | ||
| 2526 | lua_remove(L, -2); /* remove hook table */ | ||
| 2527 | } | ||
| 2528 | lua_pushstring(L, unmakemask(mask, buff)); | ||
| 2529 | ]] | ||
| 2530 | } | ||
| 2531 | |||
| 2532 | Bug{ | ||
| 2533 | what = [[Lexical gets confused with some combination of arithmetic | ||
| 2534 | operators and hexadecimal numbers]], | ||
| 2535 | report = [[Alexandra Barros, 2012/01/17]], | ||
| 2536 | since = [[5.2.0]], | ||
| 2537 | fix = [[5.2.1]], | ||
| 2538 | example = [[print(0xE+1)]], | ||
| 2539 | patch = [[ | ||
| 2540 | --- llex.c 2011/11/30 12:43:51 2.59 | ||
| 2541 | +++ llex.c 2012/01/20 18:22:50 | ||
| 2542 | @@ -223,12 +223,19 @@ | ||
| 2543 | |||
| 2544 | /* LUA_NUMBER */ | ||
| 2545 | static void read_numeral (LexState *ls, SemInfo *seminfo) { | ||
| 2546 | + const char *expo = "Ee"; | ||
| 2547 | + int first = ls->current; | ||
| 2548 | lua_assert(lisdigit(ls->current)); | ||
| 2549 | - do { | ||
| 2550 | - save_and_next(ls); | ||
| 2551 | - if (check_next(ls, "EePp")) /* exponent part? */ | ||
| 2552 | + save_and_next(ls); | ||
| 2553 | + if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ | ||
| 2554 | + expo = "Pp"; | ||
| 2555 | + for (;;) { | ||
| 2556 | + if (check_next(ls, expo)) /* exponent part? */ | ||
| 2557 | check_next(ls, "+-"); /* optional exponent sign */ | ||
| 2558 | - } while (lislalnum(ls->current) || ls->current == '.'); | ||
| 2559 | + if (lisxdigit(ls->current) || ls->current == '.') | ||
| 2560 | + save_and_next(ls); | ||
| 2561 | + else break; | ||
| 2562 | + } | ||
| 2563 | save(ls, '\0'); | ||
| 2564 | buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ | ||
| 2565 | if (!buff2d(ls->buff, &seminfo->r)) /* format error? */ | ||
| 2566 | ]] | ||
| 2567 | } | ||
| 2568 | |||
| 2569 | Bug{ | ||
| 2570 | what = [[Finalizers may call functions from a dynamic library after | ||
| 2571 | the library has been unloaded]], | ||
| 2572 | report = [[Josh Haberman, 2012/04/08]], | ||
| 2573 | since = [[5.1]], | ||
| 2574 | fix = [[5.2.1]], | ||
| 2575 | example = [[ | ||
| 2576 | local u = setmetatable({}, {__gc = function () foo() end}) | ||
| 2577 | local m = require 'mod' -- 'mod' may be any dynamic library written in C | ||
| 2578 | foo = m.foo -- 'foo' may be any function from 'mod' | ||
| 2579 | -- end program; it crashes | ||
| 2580 | ]], | ||
| 2581 | patch = [[ | ||
| 2582 | loadlib.c: | ||
| 2583 | 95c95 | ||
| 2584 | < #define LIBPREFIX "LOADLIB: " | ||
| 2585 | --- | ||
| 2586 | > #define CLIBS "_CLIBS" | ||
| 2587 | 251,266c251,256 | ||
| 2588 | < | ||
| 2589 | < static void **ll_register (lua_State *L, const char *path) { | ||
| 2590 | < void **plib; | ||
| 2591 | < lua_pushfstring(L, "%s%s", LIBPREFIX, path); | ||
| 2592 | < lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ | ||
| 2593 | < if (!lua_isnil(L, -1)) /* is there an entry? */ | ||
| 2594 | < plib = (void **)lua_touserdata(L, -1); | ||
| 2595 | < else { /* no entry yet; create one */ | ||
| 2596 | < lua_pop(L, 1); /* remove result from gettable */ | ||
| 2597 | < plib = (void **)lua_newuserdata(L, sizeof(const void *)); | ||
| 2598 | < *plib = NULL; | ||
| 2599 | < luaL_setmetatable(L, "_LOADLIB"); | ||
| 2600 | < lua_pushfstring(L, "%s%s", LIBPREFIX, path); | ||
| 2601 | < lua_pushvalue(L, -2); | ||
| 2602 | < lua_settable(L, LUA_REGISTRYINDEX); | ||
| 2603 | < } | ||
| 2604 | --- | ||
| 2605 | > static void *ll_checkclib (lua_State *L, const char *path) { | ||
| 2606 | > void *plib; | ||
| 2607 | > lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); | ||
| 2608 | > lua_getfield(L, -1, path); | ||
| 2609 | > plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ | ||
| 2610 | > lua_pop(L, 2); /* pop CLIBS table and 'plib' */ | ||
| 2611 | 270a261,270 | ||
| 2612 | > static void ll_addtoclib (lua_State *L, const char *path, void *plib) { | ||
| 2613 | > lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); | ||
| 2614 | > lua_pushlightuserdata(L, plib); | ||
| 2615 | > lua_pushvalue(L, -1); | ||
| 2616 | > lua_setfield(L, -3, path); /* CLIBS[path] = plib */ | ||
| 2617 | > lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ | ||
| 2618 | > lua_pop(L, 1); /* pop CLIBS table */ | ||
| 2619 | > } | ||
| 2620 | > | ||
| 2621 | > | ||
| 2622 | 272,273c272,273 | ||
| 2623 | < ** __gc tag method: calls library's `ll_unloadlib' function with the lib | ||
| 2624 | < ** handle | ||
| 2625 | --- | ||
| 2626 | > ** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib | ||
| 2627 | > ** handles in list CLIBS | ||
| 2628 | 276,278c276,281 | ||
| 2629 | < void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); | ||
| 2630 | < if (*lib) ll_unloadlib(*lib); | ||
| 2631 | < *lib = NULL; /* mark library as closed */ | ||
| 2632 | --- | ||
| 2633 | > int n = luaL_len(L, 1); | ||
| 2634 | > for (; n >= 1; n--) { /* for each handle, in reverse order */ | ||
| 2635 | > lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ | ||
| 2636 | > ll_unloadlib(lua_touserdata(L, -1)); | ||
| 2637 | > lua_pop(L, 1); /* pop handle */ | ||
| 2638 | > } | ||
| 2639 | 284,286c287,292 | ||
| 2640 | < void **reg = ll_register(L, path); | ||
| 2641 | < if (*reg == NULL) *reg = ll_load(L, path, *sym == '*'); | ||
| 2642 | < if (*reg == NULL) return ERRLIB; /* unable to load library */ | ||
| 2643 | --- | ||
| 2644 | > void *reg = ll_checkclib(L, path); /* check loaded C libraries */ | ||
| 2645 | > if (reg == NULL) { /* must load library? */ | ||
| 2646 | > reg = ll_load(L, path, *sym == '*'); | ||
| 2647 | > if (reg == NULL) return ERRLIB; /* unable to load library */ | ||
| 2648 | > ll_addtoclib(L, path, reg); | ||
| 2649 | > } | ||
| 2650 | 292c298 | ||
| 2651 | < lua_CFunction f = ll_sym(L, *reg, sym); | ||
| 2652 | --- | ||
| 2653 | > lua_CFunction f = ll_sym(L, reg, sym); | ||
| 2654 | 675,676c681,683 | ||
| 2655 | < /* create new type _LOADLIB */ | ||
| 2656 | < luaL_newmetatable(L, "_LOADLIB"); | ||
| 2657 | --- | ||
| 2658 | > /* create table CLIBS to keep track of loaded C libraries */ | ||
| 2659 | > luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); | ||
| 2660 | > lua_createtable(L, 0, 1); /* metatable for CLIBS */ | ||
| 2661 | 678a686 | ||
| 2662 | > lua_setmetatable(L, -2); | ||
| 2663 | ]] | ||
| 2664 | } | ||
| 2665 | |||
| 2666 | Bug{ | ||
| 2667 | what = [[wrong handling of 'nCcalls' in coroutines]], | ||
| 2668 | report = [[Alexander Gavrilov, 2012/04/18]], | ||
| 2669 | since = [[5.2.0]], | ||
| 2670 | fix = [[5.2.1]], | ||
| 2671 | example = [[ | ||
| 2672 | coroutine.wrap(function() | ||
| 2673 | print(pcall(pcall,pcall,pcall,pcall,pcall,error,3)) | ||
| 2674 | end)() | ||
| 2675 | ]], | ||
| 2676 | patch = [[ | ||
| 2677 | --- ldo.c 2011/11/29 15:55:08 2.102 | ||
| 2678 | +++ ldo.c 2012/04/26 20:38:32 | ||
| 2679 | @@ -402,8 +402,6 @@ | ||
| 2680 | int n; | ||
| 2681 | lua_assert(ci->u.c.k != NULL); /* must have a continuation */ | ||
| 2682 | lua_assert(L->nny == 0); | ||
| 2683 | - /* finish 'luaD_call' */ | ||
| 2684 | - L->nCcalls--; | ||
| 2685 | /* finish 'lua_callk' */ | ||
| 2686 | adjustresults(L, ci->nresults); | ||
| 2687 | /* call continuation function */ | ||
| 2688 | @@ -513,7 +511,6 @@ | ||
| 2689 | api_checknelems(L, n); | ||
| 2690 | firstArg = L->top - n; /* yield results come from continuation */ | ||
| 2691 | } | ||
| 2692 | - L->nCcalls--; /* finish 'luaD_call' */ | ||
| 2693 | luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ | ||
| 2694 | } | ||
| 2695 | unroll(L, NULL); | ||
| 2696 | ]] | ||
| 2697 | } | ||
| 2698 | |||
| 2699 | Bug{ | ||
| 2700 | what = [[Internal Lua values may escape through the debug API]], | ||
| 2701 | report = [[Dan Tull, 2012/04/20]], | ||
| 2702 | since = [[5.1]], | ||
| 2703 | fix = [[5.2.1]], | ||
| 2704 | example = [[ | ||
| 2705 | -- for Lua 5.1 | ||
| 2706 | local firsttime = true | ||
| 2707 | local function foo () | ||
| 2708 | if firsttime then | ||
| 2709 | firsttime = false | ||
| 2710 | return "a = 1" | ||
| 2711 | else | ||
| 2712 | for i = 1, 10 do | ||
| 2713 | print(debug.getlocal(2, i)) | ||
| 2714 | end | ||
| 2715 | end | ||
| 2716 | end | ||
| 2717 | |||
| 2718 | print(load(foo)) -- prints some lines and then seg. fault. | ||
| 2719 | ]], | ||
| 2720 | patch = [[ | ||
| 2721 | ]] | ||
| 2722 | } | ||
| 2723 | |||
| 2724 | Bug{ | ||
| 2725 | what = [[Problems when yielding from debug hooks]], | ||
| 2726 | report = [[Erik Cassel, 2012/06/05]], | ||
| 2727 | since = [[5.2.0]], | ||
| 2728 | fix = [[5.2.1]], | ||
| 2729 | example = [[ | ||
| 2730 | Set, in C, a line hook that simply yields, | ||
| 2731 | and then call any Lua function. | ||
| 2732 | You get an infinite loop of yields. | ||
| 2733 | ]], | ||
| 2734 | patch = [[ | ||
| 2735 | ]] | ||
| 2736 | } | ||
| 2737 | |||
| 2738 | |||
| 2739 | ----------------------------------------------------------------- | ||
| 2740 | -- Lua 5.2.1 | ||
| 2741 | |||
| 2742 | Bug{ | ||
| 2743 | what = [[Some patterns can overflow the C stack, due to recursion]], | ||
| 2744 | report = [[Tim Starling, 2012/07/08]], | ||
| 2745 | since = [[2.5]], | ||
| 2746 | fix = [[5.2.2]], | ||
| 2747 | example = [[print(string.find(string.rep("a", 2^20), string.rep(".?", 2^20)))]], | ||
| 2748 | patch = [[ | ||
| 2749 | ]] | ||
| 2750 | } | ||
| 2751 | |||
| 2752 | |||
| 2753 | Bug{ | ||
| 2754 | what = [['pcall' may not restore previous error function when | ||
| 2755 | inside coroutines]], | ||
| 2756 | report = [[Alexander Gavrilov, 2012/06/12]], | ||
| 2757 | since = [[5.2.0]], | ||
| 2758 | fix = [[5.2.2]], | ||
| 2759 | example = [[ | ||
| 2760 | function errfunc(x) | ||
| 2761 | return 'errfunc' | ||
| 2762 | end | ||
| 2763 | |||
| 2764 | function test(do_yield) | ||
| 2765 | print(do_yield and "yielding" or "not yielding") | ||
| 2766 | pcall(function() -- this pcall sets errfunc back to none | ||
| 2767 | if do_yield then | ||
| 2768 | coroutine.yield() -- stops errfunc from being restored | ||
| 2769 | end | ||
| 2770 | end) | ||
| 2771 | error('fail!') | ||
| 2772 | end | ||
| 2773 | |||
| 2774 | coro = coroutine.wrap(function() | ||
| 2775 | print(xpcall(test, errfunc, false)) | ||
| 2776 | print(xpcall(test, errfunc, true)) | ||
| 2777 | print(xpcall(test, errfunc, false)) | ||
| 2778 | end) | ||
| 2779 | |||
| 2780 | coro() | ||
| 2781 | --> not yielding | ||
| 2782 | --> false errfunc | ||
| 2783 | --> yielding | ||
| 2784 | coro() | ||
| 2785 | --> false temp:12: fail! <<<< should be 'errfunc' too | ||
| 2786 | --> not yielding | ||
| 2787 | --> false errfunc | ||
| 2788 | ]], | ||
| 2789 | patch = [[ | ||
| 2790 | --- ldo.c 2012/08/28 18:30:45 2.107 | ||
| 2791 | +++ ldo.c 2012/09/23 15:49:55 | ||
| 2792 | @@ -403,7 +403,11 @@ | ||
| 2793 | int n; | ||
| 2794 | lua_assert(ci->u.c.k != NULL); /* must have a continuation */ | ||
| 2795 | lua_assert(L->nny == 0); | ||
| 2796 | - /* finish 'lua_callk' */ | ||
| 2797 | + if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ | ||
| 2798 | + ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ | ||
| 2799 | + L->errfunc = ci->u.c.old_errfunc; | ||
| 2800 | + } | ||
| 2801 | + /* finish 'lua_callk'/'lua_pcall' */ | ||
| 2802 | adjustresults(L, ci->nresults); | ||
| 2803 | /* call continuation function */ | ||
| 2804 | if (!(ci->callstatus & CIST_STAT)) /* no call status? */ | ||
| 2805 | ]] | ||
| 2806 | } | ||
| 2807 | |||
| 2808 | Bug{ | ||
| 2809 | what = [[Check for garbage collector in function calls does not cover | ||
| 2810 | all paths]], | ||
| 2811 | report = [[Roberto, 2012/08/15]], | ||
| 2812 | since = [[5.2.1]], | ||
| 2813 | fix = [[5.2.2]], | ||
| 2814 | example = [[ | ||
| 2815 | See <a href="http://lua-users.org/lists/lua-l/2012-08/msg00149.html"> | ||
| 2816 | http://lua-users.org/lists/lua-l/2012-08/msg00149.html</a> | ||
| 2817 | ]], | ||
| 2818 | patch = [[ | ||
| 2819 | @@ -311,6 +311,7 @@ | ||
| 2820 | ci->top = L->top + LUA_MINSTACK; | ||
| 2821 | lua_assert(ci->top <= L->stack_last); | ||
| 2822 | ci->callstatus = 0; | ||
| 2823 | + luaC_checkGC(L); /* stack grow uses memory */ | ||
| 2824 | if (L->hookmask & LUA_MASKCALL) | ||
| 2825 | luaD_hook(L, LUA_HOOKCALL, -1); | ||
| 2826 | lua_unlock(L); | ||
| 2827 | @@ -338,6 +339,7 @@ | ||
| 2828 | ci->u.l.savedpc = p->code; /* starting point */ | ||
| 2829 | ci->callstatus = CIST_LUA; | ||
| 2830 | L->top = ci->top; | ||
| 2831 | + luaC_checkGC(L); /* stack grow uses memory */ | ||
| 2832 | if (L->hookmask & LUA_MASKCALL) | ||
| 2833 | callhook(L, ci); | ||
| 2834 | return 0; | ||
| 2835 | @@ -393,7 +395,6 @@ | ||
| 2836 | luaV_execute(L); /* call it */ | ||
| 2837 | if (!allowyield) L->nny--; | ||
| 2838 | L->nCcalls--; | ||
| 2839 | - luaC_checkGC(L); | ||
| 2840 | } | ||
| 2841 | ]] | ||
| 2842 | } | ||
| 2843 | |||
| 2844 | Bug{ | ||
| 2845 | what = [[load/loadfile returns wrong result when given an environment | ||
| 2846 | for a binary chunk with no upvalues]], | ||
| 2847 | report = [[Vladimir Strakh, 2012/11/28]], | ||
| 2848 | since = [[5.2.0]], | ||
| 2849 | fix = [[5.2.2]], | ||
| 2850 | example = [[ | ||
| 2851 | f = load(string.dump(function () return 1 end), nil, "b", {}) | ||
| 2852 | print(type(f)) --> table (whould be a function) | ||
| 2853 | ]], | ||
| 2854 | patch = [[ | ||
| 2855 | --- lbaselib.c 2012/04/27 14:13:19 1.274 | ||
| 2856 | +++ lbaselib.c 2012/12/03 20:08:15 | ||
| 2857 | @@ -244,5 +244,11 @@ | ||
| 2858 | |||
| 2859 | -static int load_aux (lua_State *L, int status) { | ||
| 2860 | - if (status == LUA_OK) | ||
| 2861 | +static int load_aux (lua_State *L, int status, int envidx) { | ||
| 2862 | + if (status == LUA_OK) { | ||
| 2863 | + if (envidx != 0) { /* 'env' parameter? */ | ||
| 2864 | + lua_pushvalue(L, envidx); /* environment for loaded function */ | ||
| 2865 | + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ | ||
| 2866 | + lua_pop(L, 1); /* remove 'env' if not used by previous call */ | ||
| 2867 | + } | ||
| 2868 | return 1; | ||
| 2869 | + } | ||
| 2870 | else { | ||
| 2871 | @@ -258,9 +264,5 @@ | ||
| 2872 | const char *mode = luaL_optstring(L, 2, NULL); | ||
| 2873 | - int env = !lua_isnone(L, 3); /* 'env' parameter? */ | ||
| 2874 | + int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ | ||
| 2875 | int status = luaL_loadfilex(L, fname, mode); | ||
| 2876 | - if (status == LUA_OK && env) { /* 'env' parameter? */ | ||
| 2877 | - lua_pushvalue(L, 3); | ||
| 2878 | - lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */ | ||
| 2879 | - } | ||
| 2880 | - return load_aux(L, status); | ||
| 2881 | + return load_aux(L, status, env); | ||
| 2882 | } | ||
| 2883 | @@ -309,5 +311,5 @@ | ||
| 2884 | size_t l; | ||
| 2885 | - int top = lua_gettop(L); | ||
| 2886 | const char *s = lua_tolstring(L, 1, &l); | ||
| 2887 | const char *mode = luaL_optstring(L, 3, "bt"); | ||
| 2888 | + int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ | ||
| 2889 | if (s != NULL) { /* loading a string? */ | ||
| 2890 | @@ -322,7 +324,3 @@ | ||
| 2891 | } | ||
| 2892 | - if (status == LUA_OK && top >= 4) { /* is there an 'env' argument */ | ||
| 2893 | - lua_pushvalue(L, 4); /* environment for loaded function */ | ||
| 2894 | - lua_setupvalue(L, -2, 1); /* set it as 1st upvalue */ | ||
| 2895 | - } | ||
| 2896 | - return load_aux(L, status); | ||
| 2897 | + return load_aux(L, status, env); | ||
| 2898 | } | ||
| 2899 | ]] | ||
| 2900 | } | ||
| 2901 | |||
| 2902 | Bug{ | ||
| 2903 | what = [[Lua does not check memory use when creating error messages]], | ||
| 2904 | report = [[John Dunn, 2012/09/24]], | ||
| 2905 | since = [[5.2.0]], | ||
| 2906 | fix = nil, | ||
| 2907 | example = [[ | ||
| 2908 | local code = "function test()\n bob.joe.larry = 23\n end" | ||
| 2909 | |||
| 2910 | load(code)() | ||
| 2911 | |||
| 2912 | -- memory will grow steadly | ||
| 2913 | for i = 1, math.huge do | ||
| 2914 | pcall(test) | ||
| 2915 | if i % 100000 == 0 then | ||
| 2916 | io.write(collectgarbage'count'*1024, "\n") | ||
| 2917 | end | ||
| 2918 | end | ||
| 2919 | ]], | ||
| 2920 | patch = [[ | ||
| 2921 | ]] | ||
| 2922 | } | ||
| 2923 | |||
| 2924 | |||
| 2925 | |||
| 2926 | |||
| 2927 | |||
| 2928 | ----------------------------------------------------------------- | ||
| 2929 | -- Lua 5.2.2 | ||
| 2930 | |||
| 2931 | |||
| 2932 | Bug{ | ||
| 2933 | what = [[stack overflow in vararg functions with many fixed | ||
| 2934 | parameters called with few arguments]], | ||
| 2935 | report = [[云风, 2013/04/17]], | ||
| 2936 | since = [[5.1]], | ||
| 2937 | fix = [[5.2.3]], | ||
| 2938 | example = [[ | ||
| 2939 | function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, | ||
| 2940 | p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, | ||
| 2941 | p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, | ||
| 2942 | p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, | ||
| 2943 | p41, p42, p43, p44, p45, p46, p48, p49, p50, ...) | ||
| 2944 | local a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14 | ||
| 2945 | end | ||
| 2946 | |||
| 2947 | f() -- seg. fault (on some machines) | ||
| 2948 | ]], | ||
| 2949 | patch = [[ | ||
| 2950 | --- ldo.c 2012/10/01 14:05:04 2.108 | ||
| 2951 | +++ ldo.c 2013/04/19 20:56:06 | ||
| 2952 | @@ -324,7 +324,7 @@ | ||
| 2953 | case LUA_TLCL: { /* Lua function: prepare its call */ | ||
| 2954 | StkId base; | ||
| 2955 | Proto *p = clLvalue(func)->p; | ||
| 2956 | - luaD_checkstack(L, p->maxstacksize); | ||
| 2957 | + luaD_checkstack(L, p->maxstacksize + p->numparams); | ||
| 2958 | func = restorestack(L, funcr); | ||
| 2959 | n = cast_int(L->top - func) - 1; /* number of real arguments */ | ||
| 2960 | for (; n < p->numparams; n++) | ||
| 2961 | ]], | ||
| 2962 | } | ||
| 2963 | |||
| 2964 | Bug{ | ||
| 2965 | what = [[garbage collector can trigger too many times in recursive loops]], | ||
| 2966 | report = [[Roberto, 2013/04/25]], | ||
| 2967 | since = [[5.2.2]], | ||
| 2968 | fix = [[5.2.3]], | ||
| 2969 | example = [[ | ||
| 2970 | function f() f() end | ||
| 2971 | f() -- it takes too long before a "stack overflow" error | ||
| 2972 | ]], | ||
| 2973 | patch = [[ | ||
| 2974 | --- lgc.c 2013/04/12 18:48:47 2.140.1.1 | ||
| 2975 | +++ lgc.c 2013/04/25 21:30:20 | ||
| 2976 | @@ -495,2 +495,3 @@ | ||
| 2977 | static lu_mem traversestack (global_State *g, lua_State *th) { | ||
| 2978 | + int n = 0; | ||
| 2979 | StkId o = th->stack; | ||
| 2980 | @@ -505,3 +506,9 @@ | ||
| 2981 | } | ||
| 2982 | - return sizeof(lua_State) + sizeof(TValue) * th->stacksize; | ||
| 2983 | + else { /* count call infos to compute size */ | ||
| 2984 | + CallInfo *ci; | ||
| 2985 | + for (ci = &th->base_ci; ci != th->ci; ci = ci->next) | ||
| 2986 | + n++; | ||
| 2987 | + } | ||
| 2988 | + return sizeof(lua_State) + sizeof(TValue) * th->stacksize + | ||
| 2989 | + sizeof(CallInfo) * n; | ||
| 2990 | } | ||
| 2991 | ]] | ||
| 2992 | } | ||
| 2993 | |||
| 2994 | -- [[]] | ||
| 2995 | Bug{ | ||
| 2996 | what = [[Wrong assert when reporting concatenation errors | ||
| 2997 | (manifests only when Lua is compiled in debug mode)]], | ||
| 2998 | report = [[Roberto, 2013/05/05]], | ||
| 2999 | since = [[?]], | ||
| 3000 | fix = [[5.2.3]], | ||
| 3001 | example = [[ | ||
| 3002 | -- only with Lua compiled in debug mode | ||
| 3003 | print({} .. 2) | ||
| 3004 | ]], | ||
| 3005 | patch = [[ | ||
| 3006 | --- ldebug.c 2013/04/12 18:48:47 2.90.1.1 | ||
| 3007 | +++ ldebug.c 2013/05/05 14:38:30 | ||
| 3008 | @@ -519,5 +519,5 @@ | ||
| 3009 | l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) { | ||
| 3010 | if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; | ||
| 3011 | - lua_assert(!ttisstring(p1) && !ttisnumber(p2)); | ||
| 3012 | + lua_assert(!ttisstring(p1) && !ttisnumber(p1)); | ||
| 3013 | luaG_typeerror(L, p1, "concatenate"); | ||
| 3014 | } | ||
| 3015 | ]] | ||
| 3016 | } | ||
| 3017 | |||
| 3018 | Bug{ | ||
| 3019 | what = [[Wrong error message in some short-cut expressions]], | ||
| 3020 | report = [[Egor Skriptunoff, 2013/05/10]], | ||
| 3021 | since = [[5.0]], | ||
| 3022 | fix = [[5.2.3]], | ||
| 3023 | example = [[ | ||
| 3024 | > a,b,c = true,true,true | ||
| 3025 | > (a and b or c)('', '') | ||
| 3026 | stdin:1: attempt to call a boolean value (global 'c') | ||
| 3027 | |||
| 3028 | (It should be global 'b' instead of 'c'.) | ||
| 3029 | ]], | ||
| 3030 | patch = [[ | ||
| 3031 | --- ldebug.c 2013/05/06 17:20:22 2.90.1.2 | ||
| 3032 | +++ ldebug.c 2013/05/14 19:52:48 | ||
| 3033 | @@ -327,12 +327,20 @@ | ||
| 3034 | } | ||
| 3035 | |||
| 3036 | |||
| 3037 | +static int filterpc (int pc, int jmptarget) { | ||
| 3038 | + if (pc < jmptarget) /* is code conditional (inside a jump)? */ | ||
| 3039 | + return -1; /* cannot know who sets that register */ | ||
| 3040 | + else return pc; /* current position sets that register */ | ||
| 3041 | +} | ||
| 3042 | + | ||
| 3043 | + | ||
| 3044 | /* | ||
| 3045 | ** try to find last instruction before 'lastpc' that modified register 'reg' | ||
| 3046 | */ | ||
| 3047 | static int findsetreg (Proto *p, int lastpc, int reg) { | ||
| 3048 | int pc; | ||
| 3049 | int setreg = -1; /* keep last instruction that changed 'reg' */ | ||
| 3050 | + int jmptarget = 0; /* any code before this address is conditional */ | ||
| 3051 | for (pc = 0; pc < lastpc; pc++) { | ||
| 3052 | Instruction i = p->code[pc]; | ||
| 3053 | OpCode op = GET_OPCODE(i); | ||
| 3054 | @@ -341,33 +349,38 @@ | ||
| 3055 | case OP_LOADNIL: { | ||
| 3056 | int b = GETARG_B(i); | ||
| 3057 | if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ | ||
| 3058 | - setreg = pc; | ||
| 3059 | + setreg = filterpc(pc, jmptarget); | ||
| 3060 | break; | ||
| 3061 | } | ||
| 3062 | case OP_TFORCALL: { | ||
| 3063 | - if (reg >= a + 2) setreg = pc; /* affect all regs above its base */ | ||
| 3064 | + if (reg >= a + 2) /* affect all regs above its base */ | ||
| 3065 | + setreg = filterpc(pc, jmptarget); | ||
| 3066 | break; | ||
| 3067 | } | ||
| 3068 | case OP_CALL: | ||
| 3069 | case OP_TAILCALL: { | ||
| 3070 | - if (reg >= a) setreg = pc; /* affect all registers above base */ | ||
| 3071 | + if (reg >= a) /* affect all registers above base */ | ||
| 3072 | + setreg = filterpc(pc, jmptarget); | ||
| 3073 | break; | ||
| 3074 | } | ||
| 3075 | case OP_JMP: { | ||
| 3076 | int b = GETARG_sBx(i); | ||
| 3077 | int dest = pc + 1 + b; | ||
| 3078 | /* jump is forward and do not skip `lastpc'? */ | ||
| 3079 | - if (pc < dest && dest <= lastpc) | ||
| 3080 | - pc += b; /* do the jump */ | ||
| 3081 | + if (pc < dest && dest <= lastpc) { | ||
| 3082 | + if (dest > jmptarget) | ||
| 3083 | + jmptarget = dest; /* update 'jmptarget' */ | ||
| 3084 | + } | ||
| 3085 | break; | ||
| 3086 | } | ||
| 3087 | case OP_TEST: { | ||
| 3088 | - if (reg == a) setreg = pc; /* jumped code can change 'a' */ | ||
| 3089 | + if (reg == a) /* jumped code can change 'a' */ | ||
| 3090 | + setreg = filterpc(pc, jmptarget); | ||
| 3091 | break; | ||
| 3092 | } | ||
| 3093 | default: | ||
| 3094 | if (testAMode(op) && reg == a) /* any instruction that set A */ | ||
| 3095 | - setreg = pc; | ||
| 3096 | + setreg = filterpc(pc, jmptarget); | ||
| 3097 | break; | ||
| 3098 | } | ||
| 3099 | } | ||
| 3100 | ]] | ||
| 3101 | } | ||
| 3102 | |||
| 3103 | Bug{ | ||
| 3104 | what = [[luac listings choke on long strings]], | ||
| 3105 | report = [[Ashwin Hirschi, 2013/07/03]], | ||
| 3106 | since = [[5.1.2]], | ||
| 3107 | fix = [[5.2.3]], | ||
| 3108 | example = [[ | ||
| 3109 | -- When you call 'luac -l' over this chunk, it chokes the output | ||
| 3110 | s="Lorem ipsum dolor sit amet, consectetur, " | ||
| 3111 | ]], | ||
| 3112 | patch = [[ | ||
| 3113 | --- luac.c 2011-11-29 15:46:33 -0200 1.69 | ||
| 3114 | +++ luac.c 2013-07-03 21:26:01 -0300 | ||
| 3115 | @@ -251,7 +251,7 @@ | ||
| 3116 | static void PrintConstant(const Proto* f, int i) | ||
| 3117 | { | ||
| 3118 | const TValue* o=&f->k[i]; | ||
| 3119 | - switch (ttype(o)) | ||
| 3120 | + switch (ttypenv(o)) | ||
| 3121 | { | ||
| 3122 | case LUA_TNIL: | ||
| 3123 | printf("nil"); | ||
| 3124 | ]] | ||
| 3125 | } | ||
| 3126 | |||
| 3127 | Bug{ | ||
| 3128 | what = [[GC can collect a long string still in use during parser]], | ||
| 3129 | report = [[Roberto, 2013/08/30]], | ||
| 3130 | since = [[5.2]], | ||
| 3131 | fix = [[5.2.3]], | ||
| 3132 | example = [[This bug is very difficult to happen (and to reproduce), | ||
| 3133 | because it depends on the GC running in a very specific way when | ||
| 3134 | parsing a source code with long (larger than 40 characters) identifiers.]], | ||
| 3135 | patch = [[ | ||
| 3136 | --- ltable.h 2013/04/12 18:48:47 2.16.1.1 | ||
| 3137 | +++ ltable.h 2013/08/30 15:34:24 | ||
| 3138 | @@ -18,4 +18,8 @@ | ||
| 3139 | #define invalidateTMcache(t) ((t)->flags = 0) | ||
| 3140 | |||
| 3141 | +/* returns the key, given the value of a table entry */ | ||
| 3142 | +#define keyfromval(v) \ | ||
| 3143 | + (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) | ||
| 3144 | + | ||
| 3145 | |||
| 3146 | LUAI_FUNC const TValue *luaH_getint (Table *t, int key); | ||
| 3147 | |||
| 3148 | --- llex.c 2013/04/12 18:48:47 2.63.1.1 | ||
| 3149 | +++ llex.c 2013/08/30 15:34:59 | ||
| 3150 | @@ -134,4 +134,7 @@ | ||
| 3151 | luaC_checkGC(L); | ||
| 3152 | } | ||
| 3153 | + else { /* string already present */ | ||
| 3154 | + ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */ | ||
| 3155 | + } | ||
| 3156 | L->top--; /* remove string from stack */ | ||
| 3157 | return ts; | ||
| 3158 | ]] | ||
| 3159 | } | ||
| 3160 | |||
| 3161 | |||
| 3162 | Bug{ | ||
| 3163 | what = [[Call to macro 'luai_userstateclose' should be done only | ||
| 3164 | after the calls to __gc methods.]], | ||
| 3165 | report = [[Jean-Luc Jumpertz, 2013/09/02]], | ||
| 3166 | since = [[ ]], | ||
| 3167 | fix = nil, | ||
| 3168 | example = [[No example]], | ||
| 3169 | patch = [[ | ||
| 3170 | --- lstate.c 2013/04/12 18:48:47 2.99.1.1 | ||
| 3171 | +++ lstate.c 2013/11/08 17:39:57 | ||
| 3172 | @@ -194,2 +194,4 @@ | ||
| 3173 | g->gcrunning = 1; /* allow gc */ | ||
| 3174 | + g->version = lua_version(NULL); | ||
| 3175 | + luai_userstateopen(L); | ||
| 3176 | } | ||
| 3177 | @@ -224,2 +226,4 @@ | ||
| 3178 | luaC_freeallobjects(L); /* collect all objects */ | ||
| 3179 | + if (g->version) /* closing a fully built state? */ | ||
| 3180 | + luai_userstateclose(L); | ||
| 3181 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); | ||
| 3182 | @@ -289,3 +293,3 @@ | ||
| 3183 | g->panic = NULL; | ||
| 3184 | - g->version = lua_version(NULL); | ||
| 3185 | + g->version = NULL; | ||
| 3186 | g->gcstate = GCSpause; | ||
| 3187 | @@ -308,4 +312,2 @@ | ||
| 3188 | } | ||
| 3189 | - else | ||
| 3190 | - luai_userstateopen(L); | ||
| 3191 | return L; | ||
| 3192 | @@ -317,3 +319,2 @@ | ||
| 3193 | lua_lock(L); | ||
| 3194 | - luai_userstateclose(L); | ||
| 3195 | close_state(L); | ||
| 3196 | ]] | ||
| 3197 | } | ||
| 3198 | |||
| 3199 | |||
| 3200 | Bug{ | ||
| 3201 | what = [[Resuming the running coroutine makes it unyieldable]], | ||
| 3202 | report = [[Florian Nücke, 2013/10/28]], | ||
| 3203 | since = [[5.2]], | ||
| 3204 | fix = [[5.2.3]], | ||
| 3205 | example = [[ | ||
| 3206 | -- should print 'true' | ||
| 3207 | print(coroutine.resume(coroutine.create(function() | ||
| 3208 | coroutine.resume(coroutine.running()) | ||
| 3209 | coroutine.yield() | ||
| 3210 | end))) | ||
| 3211 | ]], | ||
| 3212 | patch = [[ | ||
| 3213 | --- ldo.c 2013/04/19 21:03:23 2.108.1.2 | ||
| 3214 | +++ ldo.c 2013/11/08 18:20:57 | ||
| 3215 | @@ -536,2 +536,3 @@ | ||
| 3216 | int status; | ||
| 3217 | + int oldnny = L->nny; /* save 'nny' */ | ||
| 3218 | lua_lock(L); | ||
| 3219 | @@ -557,3 +558,3 @@ | ||
| 3220 | } | ||
| 3221 | - L->nny = 1; /* do not allow yields */ | ||
| 3222 | + L->nny = oldnny; /* restore 'nny' */ | ||
| 3223 | L->nCcalls--; | ||
| 3224 | ]] | ||
| 3225 | } | ||
| 3226 | |||
| 3227 | |||
| 3228 | |||
| 3229 | ----------------------------------------------------------------- | ||
| 3230 | -- Lua 5.2.3 | ||
| 3231 | |||
| 3232 | Bug{ | ||
| 3233 | what = [[compiler can optimize away overflow check in 'table.unpack']], | ||
| 3234 | report = [[Paige DePol, 2014/03/30]], | ||
| 3235 | since = [[5.1 (at least)]], | ||
| 3236 | fix = nil, | ||
| 3237 | example = [[ | ||
| 3238 | > unpack({}, 0, 2^31 - 1) | ||
| 3239 | (segfaults on some platforms with some compiler options) | ||
| 3240 | ]], | ||
| 3241 | patch = [[ | ||
| 3242 | --- ltablib.c 2013/04/12 18:48:47 1.65.1.1 | ||
| 3243 | +++ ltablib.c 2014/05/07 16:32:55 1.65.1.2 | ||
| 3244 | @@ -134,13 +135,14 @@ | ||
| 3245 | |||
| 3246 | |||
| 3247 | static int unpack (lua_State *L) { | ||
| 3248 | - int i, e, n; | ||
| 3249 | + int i, e; | ||
| 3250 | + unsigned int n; | ||
| 3251 | luaL_checktype(L, 1, LUA_TTABLE); | ||
| 3252 | i = luaL_optint(L, 2, 1); | ||
| 3253 | e = luaL_opt(L, luaL_checkint, 3, luaL_len(L, 1)); | ||
| 3254 | if (i > e) return 0; /* empty range */ | ||
| 3255 | - n = e - i + 1; /* number of elements */ | ||
| 3256 | - if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ | ||
| 3257 | + n = (unsigned int)e - (unsigned int)i; /* number of elements minus 1 */ | ||
| 3258 | + if (n > (INT_MAX - 10) || !lua_checkstack(L, ++n)) | ||
| 3259 | return luaL_error(L, "too many results to unpack"); | ||
| 3260 | lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ | ||
| 3261 | while (i++ < e) /* push arg[i + 1...e] */ | ||
| 3262 | ]] | ||
| 3263 | } | ||
| 3264 | |||
| 3265 | Bug{ | ||
| 3266 | what = [[Ephemeron table can wrongly collect entry with strong key]], | ||
| 3267 | report = [[Jörg Richter, 2014/08/22]], | ||
| 3268 | since = [[5.2]], | ||
| 3269 | fix = nil, | ||
| 3270 | example = [[ | ||
| 3271 | (This bug is very hard to reproduce, | ||
| 3272 | because it depends on a specific interleaving of | ||
| 3273 | events between the incremental collector and the program.) | ||
| 3274 | ]], | ||
| 3275 | patch = [[ | ||
| 3276 | --- lgc.c 2013/04/26 18:22:05 2.140.1.2 | ||
| 3277 | +++ lgc.c 2014/09/01 13:24:33 | ||
| 3278 | @@ -403,7 +403,7 @@ | ||
| 3279 | reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ | ||
| 3280 | } | ||
| 3281 | } | ||
| 3282 | - if (prop) | ||
| 3283 | + if (g->gcstate != GCSatomic || prop) | ||
| 3284 | linktable(h, &g->ephemeron); /* have to propagate again */ | ||
| 3285 | else if (hasclears) /* does table have white keys? */ | ||
| 3286 | linktable(h, &g->allweak); /* may have to clean white keys */ | ||
| 3287 | ]] | ||
| 3288 | } | ||
| 3289 | |||
| 3290 | Bug{ | ||
| 3291 | what = [[Chunk with too many lines can seg. fault]], | ||
| 3292 | report = [[Roberto, 2014/11/14]], | ||
| 3293 | since = [[5.1 (at least)]], | ||
| 3294 | fix = nil, | ||
| 3295 | example = [[ | ||
| 3296 | -- the cause of the bug is the use of an unitialized variable, so | ||
| 3297 | -- it cannot be reproduced reliably | ||
| 3298 | local s = string.rep("\n", 2^24) | ||
| 3299 | print(load(function () return s end)) | ||
| 3300 | ]], | ||
| 3301 | patch = [[ | ||
| 3302 | --- llex.c 2013/08/30 15:49:41 2.63.1.2 | ||
| 3303 | +++ llex.c 2015/02/09 17:05:31 | ||
| 3304 | @@ -153,5 +153,5 @@ | ||
| 3305 | next(ls); /* skip `\n\r' or `\r\n' */ | ||
| 3306 | if (++ls->linenumber >= MAX_INT) | ||
| 3307 | - luaX_syntaxerror(ls, "chunk has too many lines"); | ||
| 3308 | + lexerror(ls, "chunk has too many lines", 0); | ||
| 3309 | } | ||
| 3310 | |||
| 3311 | ]] | ||
| 3312 | } | ||
| 3313 | |||
| 3314 | |||
| 3315 | ----------------------------------------------------------------- | ||
| 3316 | -- Lua 5.3.0 | ||
| 3317 | |||
| 3318 | Bug{ | ||
| 3319 | what = [['string.format("%f")' can cause a buffer overflow | ||
| 3320 | (only when 'lua_Number' is long double!)]], | ||
| 3321 | report = [[Roberto, 2015/01/13]], | ||
| 3322 | since = [[5.3]], | ||
| 3323 | fix = nil, | ||
| 3324 | example = [[string.format("%.99f", 1e4000) -- when floats are long double]], | ||
| 3325 | patch = [[ | ||
| 3326 | --- lstrlib.c 2014/12/11 14:03:07 1.221 | ||
| 3327 | +++ lstrlib.c 2015/02/23 19:01:42 | ||
| 3328 | @@ -800,3 +800,4 @@ | ||
| 3329 | /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ | ||
| 3330 | -#define MAX_ITEM 512 | ||
| 3331 | +#define MAX_ITEM \ | ||
| 3332 | + (sizeof(lua_Number) <= 4 ? 150 : sizeof(lua_Number) <= 8 ? 450 : 5050) | ||
| 3333 | |||
| 3334 | ]] | ||
| 3335 | } | ||
| 3336 | |||
| 3337 | Bug{ | ||
| 3338 | what = [['debug.getlocal' on a coroutine suspended in a hook | ||
| 3339 | can crash the interpreter]], | ||
| 3340 | report = [[云风, 2015/02/11]], | ||
| 3341 | since = [[5.2]], | ||
| 3342 | fix = nil, | ||
| 3343 | example = [[see http://lua-users.org/lists/lua-l/2015-02/msg00146.html]], | ||
| 3344 | patch = [[ | ||
| 3345 | --- ldebug.c 2015/01/02 12:52:22 2.110 | ||
| 3346 | +++ ldebug.c 2015/02/13 16:03:23 | ||
| 3347 | @@ -49,4 +49,14 @@ | ||
| 3348 | |||
| 3349 | |||
| 3350 | +static void swapextra (lua_State *L) { | ||
| 3351 | + if (L->status == LUA_YIELD) { | ||
| 3352 | + CallInfo *ci = L->ci; /* get function that yielded */ | ||
| 3353 | + StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ | ||
| 3354 | + ci->func = restorestack(L, ci->extra); | ||
| 3355 | + ci->extra = savestack(L, temp); | ||
| 3356 | + } | ||
| 3357 | +} | ||
| 3358 | + | ||
| 3359 | + | ||
| 3360 | /* | ||
| 3361 | ** this function can be called asynchronous (e.g. during a signal) | ||
| 3362 | @@ -145,4 +155,5 @@ | ||
| 3363 | const char *name; | ||
| 3364 | lua_lock(L); | ||
| 3365 | + swapextra(L); | ||
| 3366 | if (ar == NULL) { /* information about non-active function? */ | ||
| 3367 | if (!isLfunction(L->top - 1)) /* not a Lua function? */ | ||
| 3368 | @@ -159,4 +170,5 @@ | ||
| 3369 | } | ||
| 3370 | } | ||
| 3371 | + swapextra(L); | ||
| 3372 | lua_unlock(L); | ||
| 3373 | return name; | ||
| 3374 | @@ -166,10 +178,13 @@ | ||
| 3375 | LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { | ||
| 3376 | StkId pos = 0; /* to avoid warnings */ | ||
| 3377 | - const char *name = findlocal(L, ar->i_ci, n, &pos); | ||
| 3378 | + const char *name; | ||
| 3379 | lua_lock(L); | ||
| 3380 | + swapextra(L); | ||
| 3381 | + name = findlocal(L, ar->i_ci, n, &pos); | ||
| 3382 | if (name) { | ||
| 3383 | setobjs2s(L, pos, L->top - 1); | ||
| 3384 | L->top--; /* pop value */ | ||
| 3385 | } | ||
| 3386 | + swapextra(L); | ||
| 3387 | lua_unlock(L); | ||
| 3388 | return name; | ||
| 3389 | @@ -271,4 +286,5 @@ | ||
| 3390 | StkId func; | ||
| 3391 | lua_lock(L); | ||
| 3392 | + swapextra(L); | ||
| 3393 | if (*what == '>') { | ||
| 3394 | ci = NULL; | ||
| 3395 | @@ -289,4 +305,5 @@ | ||
| 3396 | api_incr_top(L); | ||
| 3397 | } | ||
| 3398 | + swapextra(L); | ||
| 3399 | if (strchr(what, 'L')) | ||
| 3400 | collectvalidlines(L, cl); | ||
| 3401 | ]] | ||
| 3402 | } | ||
| 3403 | |||
| 3404 | |||
| 3405 | Bug{ | ||
| 3406 | what = [[suspended '__le' metamethod can give wrong result]], | ||
| 3407 | report = [[Eric Zhong, 2015/04/07]], | ||
| 3408 | since = [[5.2]], | ||
| 3409 | fix = nil, | ||
| 3410 | |||
| 3411 | example = [[ | ||
| 3412 | mt = {__le = function (a,b) coroutine.yield("yield"); return a.x <= b.x end} | ||
| 3413 | t1 = setmetatable({x=1}, mt) | ||
| 3414 | t2 = {x=2} | ||
| 3415 | co = coroutine.wrap(function (a,b) return t2 <= t1 end) | ||
| 3416 | co() | ||
| 3417 | print(co()) --> true (should be false) | ||
| 3418 | ]], | ||
| 3419 | |||
| 3420 | patch = [[ | ||
| 3421 | --- lstate.h 2014/10/30 18:53:28 2.119 | ||
| 3422 | +++ lstate.h 2015/04/13 15:58:40 | ||
| 3423 | @@ -94,6 +94,7 @@ | ||
| 3424 | #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ | ||
| 3425 | #define CIST_TAIL (1<<5) /* call was tail called */ | ||
| 3426 | #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ | ||
| 3427 | +#define CIST_LEQ (1<<7) /* using __lt for __le */ | ||
| 3428 | |||
| 3429 | #define isLua(ci) ((ci)->callstatus & CIST_LUA) | ||
| 3430 | |||
| 3431 | --- lvm.c 2014/12/27 20:30:38 2.232 | ||
| 3432 | +++ lvm.c 2015/04/13 15:51:30 | ||
| 3433 | @@ -292,9 +292,14 @@ | ||
| 3434 | return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; | ||
| 3435 | else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */ | ||
| 3436 | return res; | ||
| 3437 | - else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */ | ||
| 3438 | - luaG_ordererror(L, l, r); | ||
| 3439 | - return !res; | ||
| 3440 | + else { /* try 'lt': */ | ||
| 3441 | + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ | ||
| 3442 | + res = luaT_callorderTM(L, r, l, TM_LT); | ||
| 3443 | + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ | ||
| 3444 | + if (res < 0) | ||
| 3445 | + luaG_ordererror(L, l, r); | ||
| 3446 | + return !res; /* result is negated */ | ||
| 3447 | + } | ||
| 3448 | } | ||
| 3449 | |||
| 3450 | |||
| 3451 | @@ -553,11 +558,11 @@ | ||
| 3452 | case OP_LE: case OP_LT: case OP_EQ: { | ||
| 3453 | int res = !l_isfalse(L->top - 1); | ||
| 3454 | L->top--; | ||
| 3455 | - /* metamethod should not be called when operand is K */ | ||
| 3456 | - lua_assert(!ISK(GETARG_B(inst))); | ||
| 3457 | - if (op == OP_LE && /* "<=" using "<" instead? */ | ||
| 3458 | - ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE))) | ||
| 3459 | - res = !res; /* invert result */ | ||
| 3460 | + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ | ||
| 3461 | + lua_assert(op == OP_LE); | ||
| 3462 | + ci->callstatus ^= CIST_LEQ; /* clear mark */ | ||
| 3463 | + res = !res; /* negate result */ | ||
| 3464 | + } | ||
| 3465 | lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); | ||
| 3466 | if (res != GETARG_A(inst)) /* condition failed? */ | ||
| 3467 | ci->u.l.savedpc++; /* skip jump instruction */ | ||
| 3468 | ]] | ||
| 3469 | } | ||
| 3470 | |||
| 3471 | |||
| 3472 | Bug{ | ||
| 3473 | what = [[return hook may not see correct values for | ||
| 3474 | active local variables when function returns]], | ||
| 3475 | report = [[Philipp Janda/Peng Yi, 2015/05/19]], | ||
| 3476 | since = [[5.0]], | ||
| 3477 | fix = nil, | ||
| 3478 | example = [[ | ||
| 3479 | see messasge http://lua-users.org/lists/lua-l/2015-05/msg00376.html]], | ||
| 3480 | patch = [[ | ||
| 3481 | ]] | ||
| 3482 | } | ||
| 3483 | |||
| 3484 | |||
| 3485 | |||
| 3486 | ----------------------------------------------------------------- | ||
| 3487 | -- Lua 5.3.1 | ||
| 3488 | |||
| 3489 | Bug{ | ||
| 3490 | what = [['io.lines' does not check maximum number of options]], | ||
| 3491 | report = [[Patrick Donnell, 2015/07/10]], | ||
| 3492 | since = [[5.3.0]], | ||
| 3493 | fix = nil, | ||
| 3494 | example = [[ | ||
| 3495 | -- can segfault in some machines | ||
| 3496 | t ={}; for i = 1, 253 do t[i] = 1 end | ||
| 3497 | io.lines("someexistingfile", table.unpack(t))() | ||
| 3498 | ]], | ||
| 3499 | patch = [[ | ||
| 3500 | --- liolib.c 2015/07/07 17:03:34 2.146 | ||
| 3501 | +++ liolib.c 2015/07/15 14:40:28 2.147 | ||
| 3502 | @@ -318,8 +318,15 @@ | ||
| 3503 | static int io_readline (lua_State *L); | ||
| 3504 | |||
| 3505 | |||
| 3506 | +/* | ||
| 3507 | +** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit | ||
| 3508 | +** in the limit for upvalues of a closure) | ||
| 3509 | +*/ | ||
| 3510 | +#define MAXARGLINE 250 | ||
| 3511 | + | ||
| 3512 | static void aux_lines (lua_State *L, int toclose) { | ||
| 3513 | int n = lua_gettop(L) - 1; /* number of arguments to read */ | ||
| 3514 | + luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); | ||
| 3515 | lua_pushinteger(L, n); /* number of arguments to read */ | ||
| 3516 | lua_pushboolean(L, toclose); /* close/not close file when finished */ | ||
| 3517 | lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ | ||
| 3518 | ]] | ||
| 3519 | } | ||
| 3520 | |||
| 3521 | |||
| 3522 | ----------------------------------------------------------------- | ||
| 3523 | -- Lua 5.3.2 | ||
| 3524 | |||
| 3525 | Bug{ | ||
| 3526 | what = [[Metatable may access its own dealocated field when | ||
| 3527 | it has a self reference in __newindex]], | ||
| 3528 | report = [[actboy168@gmail.com, 2016/01/01]], | ||
| 3529 | since = [[5.3.2]], | ||
| 3530 | fix = nil, | ||
| 3531 | example = [[ | ||
| 3532 | local mt = {} | ||
| 3533 | mt.__newindex = mt | ||
| 3534 | local t = setmetatable({}, mt) | ||
| 3535 | t[1] = 1 -- will segfault on some machines | ||
| 3536 | ]], | ||
| 3537 | patch = [[ | ||
| 3538 | --- lvm.c 2015/11/23 11:30:45 2.265 | ||
| 3539 | +++ lvm.c 2016/01/01 14:34:12 | ||
| 3540 | @@ -190,18 +190,19 @@ | ||
| 3541 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | ||
| 3542 | const TValue *tm; | ||
| 3543 | if (oldval != NULL) { | ||
| 3544 | - lua_assert(ttistable(t) && ttisnil(oldval)); | ||
| 3545 | + Table *h = hvalue(t); /* save 't' table */ | ||
| 3546 | + lua_assert(ttisnil(oldval)); | ||
| 3547 | /* must check the metamethod */ | ||
| 3548 | - if ((tm = fasttm(L, hvalue(t)->metatable, TM_NEWINDEX)) == NULL && | ||
| 3549 | + if ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && | ||
| 3550 | /* no metamethod; is there a previous entry in the table? */ | ||
| 3551 | (oldval != luaO_nilobject || | ||
| 3552 | /* no previous entry; must create one. (The next test is | ||
| 3553 | always true; we only need the assignment.) */ | ||
| 3554 | - (oldval = luaH_newkey(L, hvalue(t), key), 1))) { | ||
| 3555 | + (oldval = luaH_newkey(L, h, key), 1))) { | ||
| 3556 | /* no metamethod and (now) there is an entry with given key */ | ||
| 3557 | setobj2t(L, cast(TValue *, oldval), val); | ||
| 3558 | - invalidateTMcache(hvalue(t)); | ||
| 3559 | - luaC_barrierback(L, hvalue(t), val); | ||
| 3560 | + invalidateTMcache(h); | ||
| 3561 | + luaC_barrierback(L, h, val); | ||
| 3562 | return; | ||
| 3563 | } | ||
| 3564 | /* else will try the metamethod */ | ||
| 3565 | ]] | ||
| 3566 | } | ||
| 3567 | |||
| 3568 | |||
| 3569 | Bug{ | ||
| 3570 | what = [[label between local definitions can mix-up their initializations]], | ||
| 3571 | report = [[Karel Tuma, 2016/03/01]], | ||
| 3572 | since = [[5.2]], | ||
| 3573 | fix = nil, | ||
| 3574 | example = [[ | ||
| 3575 | do | ||
| 3576 | local k = 0 | ||
| 3577 | local x | ||
| 3578 | ::foo:: | ||
| 3579 | local y -- should be reset to nil after goto, but it is not | ||
| 3580 | assert(not y) | ||
| 3581 | y = true | ||
| 3582 | k = k + 1 | ||
| 3583 | if k < 2 then goto foo end | ||
| 3584 | end | ||
| 3585 | ]], | ||
| 3586 | patch = [[ | ||
| 3587 | --- lparser.c 2015/11/02 16:09:30 2.149 | ||
| 3588 | +++ lparser.c 2016/03/03 12:03:37 | ||
| 3589 | @@ -1226,7 +1226,7 @@ | ||
| 3590 | checkrepeated(fs, ll, label); /* check for repeated labels */ | ||
| 3591 | checknext(ls, TK_DBCOLON); /* skip double colon */ | ||
| 3592 | /* create new entry for this label */ | ||
| 3593 | - l = newlabelentry(ls, ll, label, line, fs->pc); | ||
| 3594 | + l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); | ||
| 3595 | skipnoopstat(ls); /* skip other no-op statements */ | ||
| 3596 | if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ | ||
| 3597 | /* assume that locals are already out of scope */ | ||
| 3598 | ]] | ||
| 3599 | } | ||
| 3600 | |||
| 3601 | |||
| 3602 | Bug{ | ||
| 3603 | what = [['gmatch' iterator fails when called from a coroutine different | ||
| 3604 | from the one that created it]], | ||
| 3605 | report = [[Nagaev Boris, 2016/03/18]], | ||
| 3606 | since = [[5.3.2]], | ||
| 3607 | fix = nil, | ||
| 3608 | example = [[ | ||
| 3609 | local f = string.gmatch("1 2 3 4 5", "%d+") | ||
| 3610 | print(f()) --> 1 | ||
| 3611 | co = coroutine.wrap(f) | ||
| 3612 | print(co()) --> ??? (should be 2) | ||
| 3613 | ]], | ||
| 3614 | patch = [[ | ||
| 3615 | --- lstrlib.c 2015/11/25 16:28:17 1.239 | ||
| 3616 | +++ lstrlib.c 2016/04/11 15:29:41 | ||
| 3617 | @@ -688,6 +688,7 @@ | ||
| 3618 | static int gmatch_aux (lua_State *L) { | ||
| 3619 | GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); | ||
| 3620 | const char *src; | ||
| 3621 | + gm->ms.L = L; | ||
| 3622 | for (src = gm->src; src <= gm->ms.src_end; src++) { | ||
| 3623 | const char *e; | ||
| 3624 | reprepstate(&gm->ms); | ||
| 3625 | ]] | ||
| 3626 | } | ||
| 3627 | |||
| 3628 | |||
| 3629 | ----------------------------------------------------------------- | ||
| 3630 | -- Lua 5.3.3 | ||
| 3631 | |||
| 3632 | |||
| 3633 | Bug{ | ||
| 3634 | what = [[expression list with four or more expressions in | ||
| 3635 | a 'for' loop can crash the interpreter]], | ||
| 3636 | report = [[Marco Schöpl, 2016/06/17]], | ||
| 3637 | since = [[5.2]], | ||
| 3638 | fix = nil, | ||
| 3639 | example = [[ | ||
| 3640 | -- the next loop will probably crash the interpreter | ||
| 3641 | repeat until load "for _ in _,_,_,_ do local function _() end" | ||
| 3642 | ]], | ||
| 3643 | patch = [[ | ||
| 3644 | --- lparser.c 2016/05/13 19:10:16 2.153 | ||
| 3645 | +++ lparser.c 2016/06/17 19:52:48 | ||
| 3646 | @@ -323,6 +323,8 @@ | ||
| 3647 | luaK_nil(fs, reg, extra); | ||
| 3648 | } | ||
| 3649 | } | ||
| 3650 | + if (nexps > nvars) | ||
| 3651 | + ls->fs->freereg -= nexps - nvars; /* remove extra values */ | ||
| 3652 | } | ||
| 3653 | |||
| 3654 | |||
| 3655 | @@ -1160,11 +1162,8 @@ | ||
| 3656 | int nexps; | ||
| 3657 | checknext(ls, '='); | ||
| 3658 | nexps = explist(ls, &e); | ||
| 3659 | - if (nexps != nvars) { | ||
| 3660 | + if (nexps != nvars) | ||
| 3661 | adjust_assign(ls, nvars, nexps, &e); | ||
| 3662 | - if (nexps > nvars) | ||
| 3663 | - ls->fs->freereg -= nexps - nvars; /* remove extra values */ | ||
| 3664 | - } | ||
| 3665 | else { | ||
| 3666 | luaK_setoneret(ls->fs, &e); /* close last expression */ | ||
| 3667 | luaK_storevar(ls->fs, &lh->v, &e); | ||
| 3668 | ]] | ||
| 3669 | } | ||
| 3670 | |||
| 3671 | |||
| 3672 | Bug{ | ||
| 3673 | what = [[Checking a format for 'os.date' may read pass the format string]], | ||
| 3674 | report = [[Nagaev Boris, 2016/07/10]], | ||
| 3675 | since = [[5.3.3]], | ||
| 3676 | fix = nil, | ||
| 3677 | example = [[ | ||
| 3678 | This bug does not seem to happen with regular compilers. | ||
| 3679 | It needs an "interceptor" 'memcmp' function that continues | ||
| 3680 | reading memory after a difference is found.]], | ||
| 3681 | patch = [[ | ||
| 3682 | 2c2 | ||
| 3683 | < ** $Id: bugs,v 1.160 2018/05/24 20:25:14 roberto Exp roberto $ | ||
| 3684 | --- | ||
| 3685 | > ** $Id: bugs,v 1.160 2018/05/24 20:25:14 roberto Exp roberto $ | ||
| 3686 | 263c263,264 | ||
| 3687 | < for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) { | ||
| 3688 | --- | ||
| 3689 | > int convlen = (int)strlen(conv); | ||
| 3690 | > for (option = LUA_STRFTIMEOPTIONS; *option != '\0' && oplen <= convlen; option += oplen) { | ||
| 3691 | ]] | ||
| 3692 | } | ||
| 3693 | |||
| 3694 | |||
| 3695 | Bug{ | ||
| 3696 | what = [[Lua can generate wrong code in functions with too many constants]], | ||
| 3697 | report = [[Marco Schöpl, 2016/07/17]], | ||
| 3698 | since = [[5.3.3]], | ||
| 3699 | fix = nil, | ||
| 3700 | example = [[See http://lua-users.org/lists/lua-l/2016-07/msg00303.html]], | ||
| 3701 | patch = [[ | ||
| 3702 | --- lcode.c 2016/06/20 19:12:46 2.110 | ||
| 3703 | +++ lcode.c 2016/07/18 15:43:41 | ||
| 3704 | @@ -1018,8 +1018,8 @@ | ||
| 3705 | */ | ||
| 3706 | static void codebinexpval (FuncState *fs, OpCode op, | ||
| 3707 | expdesc *e1, expdesc *e2, int line) { | ||
| 3708 | - int rk1 = luaK_exp2RK(fs, e1); /* both operands are "RK" */ | ||
| 3709 | - int rk2 = luaK_exp2RK(fs, e2); | ||
| 3710 | + int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ | ||
| 3711 | + int rk1 = luaK_exp2RK(fs, e1); | ||
| 3712 | freeexps(fs, e1, e2); | ||
| 3713 | e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ | ||
| 3714 | e1->k = VRELOCABLE; /* all those operations are relocatable */ | ||
| 3715 | ]] | ||
| 3716 | } | ||
| 3717 | |||
| 3718 | |||
| 3719 | Bug{ | ||
| 3720 | what = [[When a coroutine tries to resume a non-suspended coroutine, | ||
| 3721 | it can do some mess (and break C assertions) before detecting the error]], | ||
| 3722 | report = [[Marco Schöpl, 2016/07/20]], | ||
| 3723 | since = [[ ]], | ||
| 3724 | fix = nil, | ||
| 3725 | example = [[ | ||
| 3726 | -- with C assertions on | ||
| 3727 | A = coroutine.running() | ||
| 3728 | B = coroutine.create(function() coroutine.resume(A) end) | ||
| 3729 | coroutine.resume(B) | ||
| 3730 | |||
| 3731 | -- or | ||
| 3732 | A = coroutine.wrap(function() pcall(A, _) end) | ||
| 3733 | A() | ||
| 3734 | ]], | ||
| 3735 | patch = [[ | ||
| 3736 | ]] | ||
| 3737 | } | ||
| 3738 | |||
| 3739 | |||
| 3740 | ----------------------------------------------------------------- | ||
| 3741 | -- Lua 5.3.4 | ||
| 3742 | |||
| 3743 | |||
| 3744 | Bug{ | ||
| 3745 | what = [[Wrong code for a goto followed by a label inside an 'if']], | ||
| 3746 | report = [[云风, 2017/04/13]], | ||
| 3747 | since = [[5.2]], | ||
| 3748 | fix = nil, | ||
| 3749 | example = [[ | ||
| 3750 | -- should print 32323232..., but prints only '3' | ||
| 3751 | if true then | ||
| 3752 | goto LBL | ||
| 3753 | ::loop:: | ||
| 3754 | print(2) | ||
| 3755 | ::LBL:: | ||
| 3756 | print(3) | ||
| 3757 | goto loop | ||
| 3758 | end | ||
| 3759 | ]], | ||
| 3760 | patch = [[ | ||
| 3761 | --- lparser.c 2017/04/19 17:20:42 2.155.1.1 | ||
| 3762 | +++ lparser.c 2017/04/29 18:11:40 2.155.1.2 | ||
| 3763 | @@ -1392,7 +1392,7 @@ | ||
| 3764 | luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ | ||
| 3765 | enterblock(fs, &bl, 0); /* must enter block before 'goto' */ | ||
| 3766 | gotostat(ls, v.t); /* handle goto/break */ | ||
| 3767 | - skipnoopstat(ls); /* skip other no-op statements */ | ||
| 3768 | + while (testnext(ls, ';')) {} /* skip semicolons */ | ||
| 3769 | if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ | ||
| 3770 | leaveblock(fs); | ||
| 3771 | return; /* and that is it */ | ||
| 3772 | ]] | ||
| 3773 | } | ||
| 3774 | |||
| 3775 | |||
| 3776 | Bug{ | ||
| 3777 | what = [[Lua crashes when building sequences with more than 2^30 elements.]], | ||
| 3778 | report = [[Viacheslav Usov, 2017/05/11]], | ||
| 3779 | since = [[ ]], | ||
| 3780 | fix = nil, | ||
| 3781 | example = [[ | ||
| 3782 | -- crashes if machine has enough memory | ||
| 3783 | local t = {} | ||
| 3784 | for i = 1, 0x7fffffff do | ||
| 3785 | t[i] = i | ||
| 3786 | end | ||
| 3787 | ]], | ||
| 3788 | patch = [[ | ||
| 3789 | --- ltable.c 2017/04/19 17:20:42 2.118.1.1 | ||
| 3790 | +++ ltable.c 2018/05/24 18:34:38 | ||
| 3791 | @@ -223,7 +223,9 @@ | ||
| 3792 | unsigned int na = 0; /* number of elements to go to array part */ | ||
| 3793 | unsigned int optimal = 0; /* optimal size for array part */ | ||
| 3794 | /* loop while keys can fill more than half of total size */ | ||
| 3795 | - for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) { | ||
| 3796 | + for (i = 0, twotoi = 1; | ||
| 3797 | + twotoi > 0 && *pna > twotoi / 2; | ||
| 3798 | + i++, twotoi *= 2) { | ||
| 3799 | if (nums[i] > 0) { | ||
| 3800 | a += nums[i]; | ||
| 3801 | if (a > twotoi/2) { /* more than half elements present? */ | ||
| 3802 | ]] | ||
| 3803 | } | ||
| 3804 | |||
| 3805 | |||
| 3806 | Bug{ | ||
| 3807 | what = [[Table length computation overflows for sequences larger than | ||
| 3808 | 2^31 elements.]], | ||
| 3809 | report = [[Viacheslav Usov, 2017/05/12]], | ||
| 3810 | since = [[ ]], | ||
| 3811 | fix = nil, | ||
| 3812 | example = [[ | ||
| 3813 | -- on a machine with enough memory | ||
| 3814 | local t = {} | ||
| 3815 | for i = 1, 2147483681 do | ||
| 3816 | t[i] = i | ||
| 3817 | end | ||
| 3818 | print(#t) | ||
| 3819 | ]], | ||
| 3820 | patch = [[ | ||
| 3821 | --- ltable.h 2017/04/19 17:20:42 2.23.1.1 | ||
| 3822 | +++ ltable.h 2018/05/24 19:31:50 | ||
| 3823 | @@ -56,3 +56,3 @@ | ||
| 3824 | LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); | ||
| 3825 | -LUAI_FUNC int luaH_getn (Table *t); | ||
| 3826 | +LUAI_FUNC lua_Unsigned luaH_getn (Table *t); | ||
| 3827 | |||
| 3828 | --- ltable.c 2018/05/24 19:22:37 2.118.1.2 | ||
| 3829 | +++ ltable.c 2018/05/24 19:25:05 | ||
| 3830 | @@ -614,4 +614,4 @@ | ||
| 3831 | |||
| 3832 | -static int unbound_search (Table *t, unsigned int j) { | ||
| 3833 | - unsigned int i = j; /* i is zero or a present index */ | ||
| 3834 | +static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) { | ||
| 3835 | + lua_Unsigned i = j; /* i is zero or a present index */ | ||
| 3836 | j++; | ||
| 3837 | @@ -620,3 +620,3 @@ | ||
| 3838 | i = j; | ||
| 3839 | - if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */ | ||
| 3840 | + if (j > l_castS2U(LUA_MAXINTEGER) / 2) { /* overflow? */ | ||
| 3841 | /* table was built with bad purposes: resort to linear search */ | ||
| 3842 | @@ -630,3 +630,3 @@ | ||
| 3843 | while (j - i > 1) { | ||
| 3844 | - unsigned int m = (i+j)/2; | ||
| 3845 | + lua_Unsigned m = (i+j)/2; | ||
| 3846 | if (ttisnil(luaH_getint(t, m))) j = m; | ||
| 3847 | @@ -642,3 +642,3 @@ | ||
| 3848 | */ | ||
| 3849 | -int luaH_getn (Table *t) { | ||
| 3850 | +lua_Unsigned luaH_getn (Table *t) { | ||
| 3851 | unsigned int j = t->sizearray; | ||
| 3852 | ]] | ||
| 3853 | } | ||
| 3854 | |||
| 3855 | |||
| 3856 | Bug{ | ||
| 3857 | what = [[Lua does not check GC when creating error messages]], | ||
| 3858 | report = [[Viacheslav Usov, 2017/07/06]], | ||
| 3859 | since = [[5.3.2]], | ||
| 3860 | fix = nil, | ||
| 3861 | example = [[ | ||
| 3862 | function test() | ||
| 3863 | bob.joe.larry = 23 | ||
| 3864 | end | ||
| 3865 | |||
| 3866 | -- memory will grow steadly | ||
| 3867 | for i = 1, math.huge do | ||
| 3868 | pcall(test) | ||
| 3869 | if i % 100000 == 0 then | ||
| 3870 | io.write(collectgarbage'count'*1024, "\n") | ||
| 3871 | end | ||
| 3872 | end | ||
| 3873 | ]], | ||
| 3874 | patch = [[ | ||
| 3875 | --- ldebug.c 2017/04/19 17:20:42 2.121.1.1 | ||
| 3876 | +++ ldebug.c 2017/07/10 17:08:39 | ||
| 3877 | @@ -653,6 +653,7 @@ | ||
| 3878 | CallInfo *ci = L->ci; | ||
| 3879 | const char *msg; | ||
| 3880 | va_list argp; | ||
| 3881 | + luaC_checkGC(L); /* error message uses memory */ | ||
| 3882 | va_start(argp, fmt); | ||
| 3883 | msg = luaO_pushvfstring(L, fmt, argp); /* format message */ | ||
| 3884 | va_end(argp); | ||
| 3885 | ]] | ||
| 3886 | } | ||
| 3887 | |||
| 3888 | |||
| 3889 | Bug{ | ||
| 3890 | what = [[dead keys with nil values can stay in weak tables]], | ||
| 3891 | report = [[云风 Cloud Wu, 2017/08/15]], | ||
| 3892 | since = [[5.2]], | ||
| 3893 | fix = nil, | ||
| 3894 | example = [[ | ||
| 3895 | -- The following chunk, under a memory checker like valgrind, | ||
| 3896 | -- produces a memory access violation. | ||
| 3897 | |||
| 3898 | local a = setmetatable({}, {__mode = 'kv'}) | ||
| 3899 | |||
| 3900 | a['ABCDEFGHIJKLMNOPQRSTUVWXYZ' .. 'abcdefghijklmnopqrstuvwxyz'] = {} | ||
| 3901 | a[next(a)] = nil | ||
| 3902 | collectgarbage() | ||
| 3903 | print(a['BCDEFGHIJKLMNOPQRSTUVWXYZ' .. 'abcdefghijklmnopqrstuvwxyz']) | ||
| 3904 | ]], | ||
| 3905 | patch = [[ | ||
| 3906 | --- lgc.c 2016/12/22 13:08:50 2.215 | ||
| 3907 | +++ lgc.c 2017/08/31 16:08:23 | ||
| 3908 | @@ -643,8 +643,9 @@ | ||
| 3909 | for (n = gnode(h, 0); n < limit; n++) { | ||
| 3910 | if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { | ||
| 3911 | setnilvalue(gval(n)); /* remove value ... */ | ||
| 3912 | - removeentry(n); /* and remove entry from table */ | ||
| 3913 | } | ||
| 3914 | + if (ttisnil(gval(n))) /* is entry empty? */ | ||
| 3915 | + removeentry(n); /* remove entry from table */ | ||
| 3916 | } | ||
| 3917 | } | ||
| 3918 | } | ||
| 3919 | ]] | ||
| 3920 | } | ||
| 3921 | |||
| 3922 | |||
| 3923 | Bug{ | ||
| 3924 | what = [['lua_pushcclosure' should not call the garbage collector when | ||
| 3925 | 'n' is zero.]], | ||
| 3926 | report = [[Andrew Gierth, 2017/12/05]], | ||
| 3927 | since = [[5.3.3]], | ||
| 3928 | fix = nil, | ||
| 3929 | example = [[ ]], | ||
| 3930 | patch = [[ | ||
| 3931 | --- lapi.c 2017/04/19 17:13:00 2.259.1.1 | ||
| 3932 | +++ lapi.c 2017/12/06 18:14:45 | ||
| 3933 | @@ -533,6 +533,7 @@ | ||
| 3934 | lua_lock(L); | ||
| 3935 | if (n == 0) { | ||
| 3936 | setfvalue(L->top, fn); | ||
| 3937 | + api_incr_top(L); | ||
| 3938 | } | ||
| 3939 | else { | ||
| 3940 | CClosure *cl; | ||
| 3941 | @@ -546,9 +547,9 @@ | ||
| 3942 | /* does not need barrier because closure is white */ | ||
| 3943 | } | ||
| 3944 | setclCvalue(L, L->top, cl); | ||
| 3945 | + api_incr_top(L); | ||
| 3946 | + luaC_checkGC(L); | ||
| 3947 | } | ||
| 3948 | - api_incr_top(L); | ||
| 3949 | - luaC_checkGC(L); | ||
| 3950 | lua_unlock(L); | ||
| 3951 | } | ||
| 3952 | ]] | ||
| 3953 | } | ||
| 3954 | |||
| 3955 | |||
| 3956 | Bug{ | ||
| 3957 | what = [[memory-allocation error when resizing a table can leave it | ||
| 3958 | in an inconsistent state.]], | ||
| 3959 | report = [[Roberto, 2017/12/08]], | ||
| 3960 | since = [[5.0]], | ||
| 3961 | fix = nil, | ||
| 3962 | example = [[ | ||
| 3963 | local a = {x = 1, y = 1, z = 1} | ||
| 3964 | a[1] = 10 -- goes to the hash part (which has 4 slots) | ||
| 3965 | print(a[1]) --> 10 | ||
| 3966 | |||
| 3967 | -- assume that the 2nd memory allocation from now fails | ||
| 3968 | pcall(rawset, a, 2, 20) -- forces a rehash | ||
| 3969 | |||
| 3970 | -- a[1] now exists both in the array part (because the array part | ||
| 3971 | -- grew) and in the hash part (because the allocation of the hash | ||
| 3972 | -- part failed, keeping it as it was). | ||
| 3973 | -- This makes the following traversal goes forever... | ||
| 3974 | for k,v in pairs(a) do print(k,v) end | ||
| 3975 | ]], | ||
| 3976 | patch = [[ | ||
| 3977 | --- ltable.c 2018/05/24 19:39:05 2.118.1.3 | ||
| 3978 | +++ ltable.c 2018/06/04 16:00:25 | ||
| 3979 | @@ -332,17 +332,34 @@ | ||
| 3980 | } | ||
| 3981 | |||
| 3982 | |||
| 3983 | +typedef struct { | ||
| 3984 | + Table *t; | ||
| 3985 | + unsigned int nhsize; | ||
| 3986 | +} AuxsetnodeT; | ||
| 3987 | + | ||
| 3988 | + | ||
| 3989 | +static void auxsetnode (lua_State *L, void *ud) { | ||
| 3990 | + AuxsetnodeT *asn = cast(AuxsetnodeT *, ud); | ||
| 3991 | + setnodevector(L, asn->t, asn->nhsize); | ||
| 3992 | +} | ||
| 3993 | + | ||
| 3994 | + | ||
| 3995 | void luaH_resize (lua_State *L, Table *t, unsigned int nasize, | ||
| 3996 | unsigned int nhsize) { | ||
| 3997 | unsigned int i; | ||
| 3998 | int j; | ||
| 3999 | + AuxsetnodeT asn; | ||
| 4000 | unsigned int oldasize = t->sizearray; | ||
| 4001 | int oldhsize = allocsizenode(t); | ||
| 4002 | Node *nold = t->node; /* save old hash ... */ | ||
| 4003 | if (nasize > oldasize) /* array part must grow? */ | ||
| 4004 | setarrayvector(L, t, nasize); | ||
| 4005 | /* create new hash part with appropriate size */ | ||
| 4006 | - setnodevector(L, t, nhsize); | ||
| 4007 | + asn.t = t; asn.nhsize = nhsize; | ||
| 4008 | + if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) { /* mem. error? */ | ||
| 4009 | + setarrayvector(L, t, oldasize); /* array back to its original size */ | ||
| 4010 | + luaD_throw(L, LUA_ERRMEM); /* rethrow memory error */ | ||
| 4011 | + } | ||
| 4012 | if (nasize < oldasize) { /* array part must shrink? */ | ||
| 4013 | t->sizearray = nasize; | ||
| 4014 | /* re-insert elements from vanishing slice */ | ||
| 4015 | ]] | ||
| 4016 | } | ||
| 4017 | |||
| 4018 | |||
| 4019 | |||
| 4020 | --[=[ | ||
| 4021 | Bug{ | ||
| 4022 | what = [[Long brackets with a huge number of '=' overflow some | ||
| 4023 | internal buffer arithmetic]], | ||
| 4024 | report = [[Marco, 2018/12/12]], | ||
| 4025 | since = [[5.1]], | ||
| 4026 | fix = nil, | ||
| 4027 | example = [[ | ||
| 4028 | local eqs = string.rep("=", 0x3ffffffe) | ||
| 4029 | local code = "return [" .. eqs .. "[a]" .. eqs .. "]" | ||
| 4030 | print(#assert(load(code))()) | ||
| 4031 | ]], | ||
| 4032 | patch = [[ | ||
| 4033 | ]] | ||
| 4034 | } | ||
| 4035 | ]=] | ||
| 4036 | |||
| 4037 | |||
| 4038 | |||
| 4039 | |||
| 4040 | --[=[ | ||
| 4041 | Bug{ | ||
| 4042 | what = [[ ]], | ||
| 4043 | report = [[ ]], | ||
| 4044 | since = [[ ]], | ||
| 4045 | fix = nil, | ||
| 4046 | example = [[ ]], | ||
| 4047 | patch = [[ | ||
| 4048 | ]] | ||
| 4049 | } | ||
| 4050 | ]=] | ||
| 4051 | |||
| 4052 | |||
