diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-03-29 15:10:50 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-03-29 15:10:50 -0300 |
| commit | 88a50ffa715483e7187c0d7d6caaf708ebacf756 (patch) | |
| tree | abd032613bb066ebf4b4d3d2cb2e031347945c0a | |
| parent | 86a8e74824b3ec7918e3dbeaff222bb1ea1ec22f (diff) | |
| download | lua-88a50ffa715483e7187c0d7d6caaf708ebacf756.tar.gz lua-88a50ffa715483e7187c0d7d6caaf708ebacf756.tar.bz2 lua-88a50ffa715483e7187c0d7d6caaf708ebacf756.zip | |
Fixed dangling 'StkId' in 'luaV_finishget'
Bug introduced in 05932567.
| -rw-r--r-- | lobject.h | 2 | ||||
| -rw-r--r-- | ltm.c | 43 | ||||
| -rw-r--r-- | ltm.h | 4 | ||||
| -rw-r--r-- | lvm.c | 10 | ||||
| -rw-r--r-- | testes/events.lua | 9 |
5 files changed, 42 insertions, 26 deletions
| @@ -256,6 +256,8 @@ typedef union { | |||
| 256 | 256 | ||
| 257 | 257 | ||
| 258 | #define l_isfalse(o) (ttisfalse(o) || ttisnil(o)) | 258 | #define l_isfalse(o) (ttisfalse(o) || ttisnil(o)) |
| 259 | #define tagisfalse(t) ((t) == LUA_VFALSE || novariant(t) == LUA_TNIL) | ||
| 260 | |||
| 259 | 261 | ||
| 260 | 262 | ||
| 261 | #define setbfvalue(obj) settt_(obj, LUA_VFALSE) | 263 | #define setbfvalue(obj) settt_(obj, LUA_VFALSE) |
| @@ -116,8 +116,8 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, | |||
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | 118 | ||
| 119 | void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, | 119 | int luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, |
| 120 | const TValue *p2, StkId res) { | 120 | const TValue *p2, StkId res) { |
| 121 | ptrdiff_t result = savestack(L, res); | 121 | ptrdiff_t result = savestack(L, res); |
| 122 | StkId func = L->top.p; | 122 | StkId func = L->top.p; |
| 123 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ | 123 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ |
| @@ -131,6 +131,7 @@ void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, | |||
| 131 | luaD_callnoyield(L, func, 1); | 131 | luaD_callnoyield(L, func, 1); |
| 132 | res = restorestack(L, result); | 132 | res = restorestack(L, result); |
| 133 | setobjs2s(L, res, --L->top.p); /* move result to its place */ | 133 | setobjs2s(L, res, --L->top.p); /* move result to its place */ |
| 134 | return ttypetag(s2v(res)); /* return tag of the result */ | ||
| 134 | } | 135 | } |
| 135 | 136 | ||
| 136 | 137 | ||
| @@ -139,15 +140,16 @@ static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
| 139 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ | 140 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ |
| 140 | if (notm(tm)) | 141 | if (notm(tm)) |
| 141 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ | 142 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ |
| 142 | if (notm(tm)) return 0; | 143 | if (notm(tm)) |
| 143 | luaT_callTMres(L, tm, p1, p2, res); | 144 | return -1; /* tag method not found */ |
| 144 | return 1; | 145 | else /* call tag method and return the tag of the result */ |
| 146 | return luaT_callTMres(L, tm, p1, p2, res); | ||
| 145 | } | 147 | } |
| 146 | 148 | ||
| 147 | 149 | ||
| 148 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, | 150 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, |
| 149 | StkId res, TMS event) { | 151 | StkId res, TMS event) { |
| 150 | if (l_unlikely(!callbinTM(L, p1, p2, res, event))) { | 152 | if (l_unlikely(callbinTM(L, p1, p2, res, event) < 0)) { |
| 151 | switch (event) { | 153 | switch (event) { |
| 152 | case TM_BAND: case TM_BOR: case TM_BXOR: | 154 | case TM_BAND: case TM_BOR: case TM_BXOR: |
| 153 | case TM_SHL: case TM_SHR: case TM_BNOT: { | 155 | case TM_SHL: case TM_SHR: case TM_BNOT: { |
| @@ -164,11 +166,14 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
| 164 | } | 166 | } |
| 165 | 167 | ||
| 166 | 168 | ||
| 169 | /* | ||
| 170 | ** The use of 'p1' after 'callbinTM' is safe because, when a tag | ||
| 171 | ** method is not found, 'callbinTM' cannot change the stack. | ||
| 172 | */ | ||
| 167 | void luaT_tryconcatTM (lua_State *L) { | 173 | void luaT_tryconcatTM (lua_State *L) { |
| 168 | StkId top = L->top.p; | 174 | StkId p1 = L->top.p - 2; /* first argument */ |
| 169 | if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, | 175 | if (l_unlikely(callbinTM(L, s2v(p1), s2v(p1 + 1), p1, TM_CONCAT) < 0)) |
| 170 | TM_CONCAT))) | 176 | luaG_concaterror(L, s2v(p1), s2v(p1 + 1)); |
| 171 | luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); | ||
| 172 | } | 177 | } |
| 173 | 178 | ||
| 174 | 179 | ||
| @@ -200,17 +205,17 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2, | |||
| 200 | */ | 205 | */ |
| 201 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, | 206 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, |
| 202 | TMS event) { | 207 | TMS event) { |
| 203 | if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */ | 208 | int tag = callbinTM(L, p1, p2, L->top.p, event); /* try original event */ |
| 204 | return !l_isfalse(s2v(L->top.p)); | 209 | if (tag >= 0) /* found tag method? */ |
| 210 | return !tagisfalse(tag); | ||
| 205 | #if defined(LUA_COMPAT_LT_LE) | 211 | #if defined(LUA_COMPAT_LT_LE) |
| 206 | else if (event == TM_LE) { | 212 | else if (event == TM_LE) { |
| 207 | /* try '!(p2 < p1)' for '(p1 <= p2)' */ | 213 | /* try '!(p2 < p1)' for '(p1 <= p2)' */ |
| 208 | L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ | 214 | L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ |
| 209 | if (callbinTM(L, p2, p1, L->top.p, TM_LT)) { | 215 | tag = callbinTM(L, p2, p1, L->top.p, TM_LT); |
| 210 | L->ci->callstatus ^= CIST_LEQ; /* clear mark */ | 216 | L->ci->callstatus ^= CIST_LEQ; /* clear mark */ |
| 211 | return l_isfalse(s2v(L->top.p)); | 217 | if (tag >= 0) /* found tag method? */ |
| 212 | } | 218 | return tagisfalse(tag); |
| 213 | /* else error will remove this 'ci'; no need to clear mark */ | ||
| 214 | } | 219 | } |
| 215 | #endif | 220 | #endif |
| 216 | luaG_ordererror(L, p1, p2); /* no metamethod found */ | 221 | luaG_ordererror(L, p1, p2); /* no metamethod found */ |
| @@ -81,8 +81,8 @@ LUAI_FUNC void luaT_init (lua_State *L); | |||
| 81 | 81 | ||
| 82 | LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, | 82 | LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, |
| 83 | const TValue *p2, const TValue *p3); | 83 | const TValue *p2, const TValue *p3); |
| 84 | LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f, | 84 | LUAI_FUNC int luaT_callTMres (lua_State *L, const TValue *f, |
| 85 | const TValue *p1, const TValue *p2, StkId p3); | 85 | const TValue *p1, const TValue *p2, StkId p3); |
| 86 | LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, | 86 | LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, |
| 87 | StkId res, TMS event); | 87 | StkId res, TMS event); |
| 88 | LUAI_FUNC void luaT_tryconcatTM (lua_State *L); | 88 | LUAI_FUNC void luaT_tryconcatTM (lua_State *L); |
| @@ -308,8 +308,8 @@ int luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
| 308 | /* else will try the metamethod */ | 308 | /* else will try the metamethod */ |
| 309 | } | 309 | } |
| 310 | if (ttisfunction(tm)) { /* is metamethod a function? */ | 310 | if (ttisfunction(tm)) { /* is metamethod a function? */ |
| 311 | luaT_callTMres(L, tm, t, key, val); /* call it */ | 311 | tag = luaT_callTMres(L, tm, t, key, val); /* call it */ |
| 312 | return ttypetag(s2v(val)); | 312 | return tag; /* return tag of the result */ |
| 313 | } | 313 | } |
| 314 | t = tm; /* else try to access 'tm[key]' */ | 314 | t = tm; /* else try to access 'tm[key]' */ |
| 315 | luaV_fastget(t, key, s2v(val), luaH_get, tag); | 315 | luaV_fastget(t, key, s2v(val), luaH_get, tag); |
| @@ -606,8 +606,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { | |||
| 606 | if (tm == NULL) /* no TM? */ | 606 | if (tm == NULL) /* no TM? */ |
| 607 | return 0; /* objects are different */ | 607 | return 0; /* objects are different */ |
| 608 | else { | 608 | else { |
| 609 | luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */ | 609 | int tag = luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */ |
| 610 | return !l_isfalse(s2v(L->top.p)); | 610 | return !tagisfalse(tag); |
| 611 | } | 611 | } |
| 612 | } | 612 | } |
| 613 | 613 | ||
| @@ -914,7 +914,7 @@ void luaV_finishOp (lua_State *L) { | |||
| 914 | 914 | ||
| 915 | /* | 915 | /* |
| 916 | ** Auxiliary function for arithmetic operations over floats and others | 916 | ** Auxiliary function for arithmetic operations over floats and others |
| 917 | ** with two register operands. | 917 | ** with two operands. |
| 918 | */ | 918 | */ |
| 919 | #define op_arithf_aux(L,v1,v2,fop) { \ | 919 | #define op_arithf_aux(L,v1,v2,fop) { \ |
| 920 | lua_Number n1; lua_Number n2; \ | 920 | lua_Number n1; lua_Number n2; \ |
diff --git a/testes/events.lua b/testes/events.lua index 8d8563b9..5360ac30 100644 --- a/testes/events.lua +++ b/testes/events.lua | |||
| @@ -248,6 +248,15 @@ end | |||
| 248 | test(Op(1), Op(2), Op(3)) | 248 | test(Op(1), Op(2), Op(3)) |
| 249 | 249 | ||
| 250 | 250 | ||
| 251 | do -- test nil as false | ||
| 252 | local x = setmetatable({12}, {__eq= function (a,b) | ||
| 253 | return a[1] == b[1] or nil | ||
| 254 | end}) | ||
| 255 | assert(not (x == {20})) | ||
| 256 | assert(x == {12}) | ||
| 257 | end | ||
| 258 | |||
| 259 | |||
| 251 | -- test `partial order' | 260 | -- test `partial order' |
| 252 | 261 | ||
| 253 | local function rawSet(x) | 262 | local function rawSet(x) |
