aboutsummaryrefslogtreecommitdiff
path: root/lvm.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2015-04-10 14:56:25 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2015-04-10 14:56:25 -0300
commitae76c39712852d14514f9ef19ac332e961749d93 (patch)
tree33fbd2d0a5c375048eade2a14c0cb606a8c5bba4 /lvm.c
parent0d4a1f71db1400a21654fc46b7e93a27db7641ae (diff)
downloadlua-ae76c39712852d14514f9ef19ac332e961749d93.tar.gz
lua-ae76c39712852d14514f9ef19ac332e961749d93.tar.bz2
lua-ae76c39712852d14514f9ef19ac332e961749d93.zip
Bug: suspended '__le' metamethod can give wrong result
Diffstat (limited to 'lvm.c')
-rw-r--r--lvm.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/lvm.c b/lvm.c
index c1e4fd09..1025e885 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lvm.c,v 2.237 2015/03/07 19:30:16 roberto Exp roberto $ 2** $Id: lvm.c,v 2.238 2015/03/30 15:45:01 roberto Exp roberto $
3** Lua virtual machine 3** Lua virtual machine
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -262,7 +262,12 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
262 262
263 263
264/* 264/*
265** Main operation less than or equal to; return 'l <= r'. 265** Main operation less than or equal to; return 'l <= r'. If it needs
266** a metamethod and there is no '__le', try '__lt', based on
267** l <= r iff !(r < l) (assuming a total order). If the metamethod
268** yields during this substitution, the continuation has to know
269** about it (to negate the result of r<l); bit CIST_LEQ in the call
270** status keeps that information.
266*/ 271*/
267int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { 272int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
268 int res; 273 int res;
@@ -273,11 +278,16 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
273 return luai_numle(nl, nr); 278 return luai_numle(nl, nr);
274 else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ 279 else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
275 return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; 280 return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
276 else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */ 281 else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */
277 return res; 282 return res;
278 else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */ 283 else { /* try 'lt': */
279 luaG_ordererror(L, l, r); 284 L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
280 return !res; 285 res = luaT_callorderTM(L, r, l, TM_LT);
286 L->ci->callstatus ^= CIST_LEQ; /* clear mark */
287 if (res < 0)
288 luaG_ordererror(L, l, r);
289 return !res; /* result is negated */
290 }
281} 291}
282 292
283 293
@@ -542,11 +552,11 @@ void luaV_finishOp (lua_State *L) {
542 case OP_LE: case OP_LT: case OP_EQ: { 552 case OP_LE: case OP_LT: case OP_EQ: {
543 int res = !l_isfalse(L->top - 1); 553 int res = !l_isfalse(L->top - 1);
544 L->top--; 554 L->top--;
545 /* metamethod should not be called when operand is K */ 555 if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
546 lua_assert(!ISK(GETARG_B(inst))); 556 lua_assert(op == OP_LE);
547 if (op == OP_LE && /* "<=" using "<" instead? */ 557 ci->callstatus ^= CIST_LEQ; /* clear mark */
548 ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE))) 558 res = !res; /* negate result */
549 res = !res; /* invert result */ 559 }
550 lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); 560 lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
551 if (res != GETARG_A(inst)) /* condition failed? */ 561 if (res != GETARG_A(inst)) /* condition failed? */
552 ci->u.l.savedpc++; /* skip jump instruction */ 562 ci->u.l.savedpc++; /* skip jump instruction */