diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-04-10 14:56:25 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-04-10 14:56:25 -0300 |
| commit | ae76c39712852d14514f9ef19ac332e961749d93 (patch) | |
| tree | 33fbd2d0a5c375048eade2a14c0cb606a8c5bba4 /bugs | |
| parent | 0d4a1f71db1400a21654fc46b7e93a27db7641ae (diff) | |
| download | lua-ae76c39712852d14514f9ef19ac332e961749d93.tar.gz lua-ae76c39712852d14514f9ef19ac332e961749d93.tar.bz2 lua-ae76c39712852d14514f9ef19ac332e961749d93.zip | |
Bug: suspended '__le' metamethod can give wrong result
Diffstat (limited to 'bugs')
| -rw-r--r-- | bugs | 67 |
1 files changed, 67 insertions, 0 deletions
| @@ -3376,6 +3376,73 @@ patch = [[ | |||
| 3376 | } | 3376 | } |
| 3377 | 3377 | ||
| 3378 | 3378 | ||
| 3379 | Bug{ | ||
| 3380 | what = [[suspended '__le' metamethod can give wrong result]], | ||
| 3381 | report = [[Eric Zhong, 2015/04/07]], | ||
| 3382 | since = [[5.2]], | ||
| 3383 | fix = nil, | ||
| 3384 | |||
| 3385 | example = [[ | ||
| 3386 | mt = {__le = function (a,b) coroutine.yield("yield"); return a.x <= b.x end} | ||
| 3387 | t1 = setmetatable({x=1}, mt) | ||
| 3388 | t2 = {x=2} | ||
| 3389 | co = coroutine.wrap(function (a,b) return t2 <= t1 end) | ||
| 3390 | co() | ||
| 3391 | print(co()) --> true (should be false) | ||
| 3392 | ]], | ||
| 3393 | |||
| 3394 | patch = [[ | ||
| 3395 | --- lstate.h 2015/03/04 13:31:21 2.120 | ||
| 3396 | +++ lstate.h 2015/04/08 16:30:40 | ||
| 3397 | @@ -94,6 +94,7 @@ | ||
| 3398 | #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ | ||
| 3399 | #define CIST_TAIL (1<<5) /* call was tail called */ | ||
| 3400 | #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ | ||
| 3401 | +#define CIST_LEQ (1<<7) /* using __lt for __le */ | ||
| 3402 | |||
| 3403 | #define isLua(ci) ((ci)->callstatus & CIST_LUA) | ||
| 3404 | |||
| 3405 | |||
| 3406 | --- lvm.c 2015/03/30 15:45:01 2.238 | ||
| 3407 | +++ lvm.c 2015/04/09 15:30:13 | ||
| 3408 | @@ -275,9 +275,14 @@ | ||
| 3409 | return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; | ||
| 3410 | else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */ | ||
| 3411 | return res; | ||
| 3412 | - else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */ | ||
| 3413 | - luaG_ordererror(L, l, r); | ||
| 3414 | - return !res; | ||
| 3415 | + else { /* try 'lt': */ | ||
| 3416 | + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ | ||
| 3417 | + res = luaT_callorderTM(L, r, l, TM_LT); | ||
| 3418 | + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ | ||
| 3419 | + if (res < 0) | ||
| 3420 | + luaG_ordererror(L, l, r); | ||
| 3421 | + return !res; /* result is negated */ | ||
| 3422 | + } | ||
| 3423 | } | ||
| 3424 | |||
| 3425 | @@ -542,11 +547,11 @@ | ||
| 3426 | case OP_LE: case OP_LT: case OP_EQ: { | ||
| 3427 | int res = !l_isfalse(L->top - 1); | ||
| 3428 | L->top--; | ||
| 3429 | - /* metamethod should not be called when operand is K */ | ||
| 3430 | - lua_assert(!ISK(GETARG_B(inst))); | ||
| 3431 | - if (op == OP_LE && /* "<=" using "<" instead? */ | ||
| 3432 | - ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE))) | ||
| 3433 | - res = !res; /* invert result */ | ||
| 3434 | + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ | ||
| 3435 | + lua_assert(op == OP_LE); | ||
| 3436 | + ci->callstatus ^= CIST_LEQ; /* clear mark */ | ||
| 3437 | + res = !res; /* negate result */ | ||
| 3438 | + } | ||
| 3439 | lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); | ||
| 3440 | if (res != GETARG_A(inst)) /* condition failed? */ | ||
| 3441 | ci->u.l.savedpc++; /* skip jump instruction */ | ||
| 3442 | ]] | ||
| 3443 | } | ||
| 3444 | |||
| 3445 | |||
| 3379 | --[=[ | 3446 | --[=[ |
| 3380 | Bug{ | 3447 | Bug{ |
| 3381 | what = [[ ]], | 3448 | what = [[ ]], |
