small bug in 'luaV_concat' (L->top was left incorrect in some cases)

This commit is contained in:
Roberto Ierusalimschy 2009-05-27 14:11:27 -03:00
parent 139d562861
commit 57f8414de1
4 changed files with 28 additions and 29 deletions

5
lapi.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lapi.c,v 2.75 2009/04/17 14:28:06 roberto Exp roberto $ ** $Id: lapi.c,v 2.76 2009/04/17 22:00:01 roberto Exp $
** Lua API ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -1017,8 +1017,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
api_checknelems(L, n); api_checknelems(L, n);
if (n >= 2) { if (n >= 2) {
luaC_checkGC(L); luaC_checkGC(L);
luaV_concat(L, n, cast_int(L->top - L->base) - 1); luaV_concat(L, n);
L->top -= (n-1);
} }
else if (n == 0) { /* push empty string */ else if (n == 0) { /* push empty string */
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lobject.c,v 2.28 2008/01/30 18:05:23 roberto Exp roberto $ ** $Id: lobject.c,v 2.29 2009/02/19 17:18:25 roberto Exp $
** Some generic functions over Lua objects ** Some generic functions over Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -162,8 +162,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
fmt = e+2; fmt = e+2;
} }
pushstr(L, fmt); pushstr(L, fmt);
luaV_concat(L, n+1, cast_int(L->top - L->base) - 1); luaV_concat(L, n+1);
L->top -= n;
return svalue(L->top - 1); return svalue(L->top - 1);
} }

43
lvm.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.c,v 2.87 2009/04/30 17:42:21 roberto Exp roberto $ ** $Id: lvm.c,v 2.88 2009/05/22 15:19:54 roberto Exp $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -264,24 +264,22 @@ int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) {
} }
void luaV_concat (lua_State *L, int total, int last) { void luaV_concat (lua_State *L, int total) {
lua_assert(total >= 2);
do { do {
StkId top = L->base + last + 1; StkId top = L->top;
int n = 2; /* number of elements handled in this pass (at least 2) */ int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
L->top = top; /* set top to current position (in case of yield) */
if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
luaG_concaterror(L, top-2, top-1); luaG_concaterror(L, top-2, top-1);
L->top = L->ci->top; /* restore top */
}
else if (tsvalue(top-1)->len == 0) { /* second operand is empty? */
(void)tostring(L, top - 2); /* result is first operand */ ;
} }
else if (tsvalue(top-1)->len == 0) /* second operand is empty? */
(void)tostring(L, top - 2); /* result is first operand */
else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) {
setsvalue2s(L, top-2, rawtsvalue(top-1)); /* result is second op. */ setsvalue2s(L, top-2, rawtsvalue(top-1)); /* result is second op. */
} }
else { else {
/* at least two (non-empty) string values; get as many as possible */ /* at least two non-empty string values; get as many as possible */
size_t tl = tsvalue(top-1)->len; size_t tl = tsvalue(top-1)->len;
char *buffer; char *buffer;
int i; int i;
@ -300,8 +298,8 @@ void luaV_concat (lua_State *L, int total, int last) {
} }
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
} }
total -= n-1; /* got `n' strings to create 1 new */ total -= n-1; /* got 'n' strings to create 1 new */
last -= n-1; L->top -= n-1; /* poped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */ } while (total > 1); /* repeat until only 1 result left */
} }
@ -381,16 +379,17 @@ void luaV_finishOp (lua_State *L) {
break; break;
} }
case OP_CONCAT: { case OP_CONCAT: {
StkId top = L->top - 1; /* top when __concat was called */ StkId top = L->top - 1; /* top when 'call_binTM' was called */
int last = cast_int(top - ci->base) - 2; /* last element and ... */ int b = GETARG_B(inst); /* first element to concatenate */
int b = GETARG_B(inst); /* ... first element to concatenate */ int total = top - 1 - (ci->base + b); /* elements yet to concatenate */
int total = last - b + 1; /* number of elements to concatenate */
setobj2s(L, top - 2, top); /* put TM result in proper position */ setobj2s(L, top - 2, top); /* put TM result in proper position */
L->top = ci->top; /* correct top */ if (total > 1) { /* are there elements to concat? */
if (total > 1) /* are there elements to concat? */ L->top = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total, last); /* concat them (may yield again) */ luaV_concat(L, total); /* concat them (may yield again) */
}
/* move final result to final position */ /* move final result to final position */
setobj2s(L, ci->base + GETARG_A(inst), ci->base + b); setobj2s(L, ci->base + GETARG_A(inst), L->top - 1);
L->top = ci->top; /* restore top */
break; break;
} }
case OP_TFORCALL: { case OP_TFORCALL: {
@ -586,7 +585,9 @@ void luaV_execute (lua_State *L) {
case OP_CONCAT: { case OP_CONCAT: {
int b = GETARG_B(i); int b = GETARG_B(i);
int c = GETARG_C(i); int c = GETARG_C(i);
Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); L->top = base + c + 1; /* mark the end of concat operands */
Protect(luaV_concat(L, c-b+1); luaC_checkGC(L));
L->top = ci->top; /* restore top */
setobjs2s(L, RA(i), base+b); setobjs2s(L, RA(i), base+b);
continue; continue;
} }

4
lvm.h
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.h,v 2.7 2008/08/26 13:27:42 roberto Exp roberto $ ** $Id: lvm.h,v 2.8 2009/03/10 17:14:37 roberto Exp $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -34,6 +34,6 @@ LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
StkId val); StkId val);
LUAI_FUNC void luaV_finishOp (lua_State *L); LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L); LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); LUAI_FUNC void luaV_concat (lua_State *L, int total);
#endif #endif