diff options
Diffstat (limited to '')
47 files changed, 552 insertions, 414 deletions
@@ -681,6 +681,11 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) { | |||
681 | } | 681 | } |
682 | 682 | ||
683 | 683 | ||
684 | /* | ||
685 | ** The following function assumes that the registry cannot be a weak | ||
686 | ** table, so that en mergency collection while using the global table | ||
687 | ** cannot collect it. | ||
688 | */ | ||
684 | static void getGlobalTable (lua_State *L, TValue *gt) { | 689 | static void getGlobalTable (lua_State *L, TValue *gt) { |
685 | Table *registry = hvalue(&G(L)->l_registry); | 690 | Table *registry = hvalue(&G(L)->l_registry); |
686 | lu_byte tag = luaH_getint(registry, LUA_RIDX_GLOBALS, gt); | 691 | lu_byte tag = luaH_getint(registry, LUA_RIDX_GLOBALS, gt); |
@@ -883,9 +888,8 @@ LUA_API void lua_settable (lua_State *L, int idx) { | |||
883 | api_checkpop(L, 2); | 888 | api_checkpop(L, 2); |
884 | t = index2value(L, idx); | 889 | t = index2value(L, idx); |
885 | luaV_fastset(t, s2v(L->top.p - 2), s2v(L->top.p - 1), hres, luaH_pset); | 890 | luaV_fastset(t, s2v(L->top.p - 2), s2v(L->top.p - 1), hres, luaH_pset); |
886 | if (hres == HOK) { | 891 | if (hres == HOK) |
887 | luaV_finishfastset(L, t, s2v(L->top.p - 1)); | 892 | luaV_finishfastset(L, t, s2v(L->top.p - 1)); |
888 | } | ||
889 | else | 893 | else |
890 | luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), hres); | 894 | luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), hres); |
891 | L->top.p -= 2; /* pop index and value */ | 895 | L->top.p -= 2; /* pop index and value */ |
@@ -165,7 +165,11 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, | |||
165 | 165 | ||
166 | 166 | ||
167 | /* push the value used to represent failure/error */ | 167 | /* push the value used to represent failure/error */ |
168 | #if defined(LUA_FAILISFALSE) | ||
169 | #define luaL_pushfail(L) lua_pushboolean(L, 0) | ||
170 | #else | ||
168 | #define luaL_pushfail(L) lua_pushnil(L) | 171 | #define luaL_pushfail(L) lua_pushnil(L) |
172 | #endif | ||
169 | 173 | ||
170 | 174 | ||
171 | 175 | ||
@@ -33,6 +33,8 @@ | |||
33 | 33 | ||
34 | #define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL) | 34 | #define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL) |
35 | 35 | ||
36 | static const char strlocal[] = "local"; | ||
37 | static const char strupval[] = "upvalue"; | ||
36 | 38 | ||
37 | static const char *funcnamefromcall (lua_State *L, CallInfo *ci, | 39 | static const char *funcnamefromcall (lua_State *L, CallInfo *ci, |
38 | const char **name); | 40 | const char **name); |
@@ -505,7 +507,7 @@ static const char *basicgetobjname (const Proto *p, int *ppc, int reg, | |||
505 | int pc = *ppc; | 507 | int pc = *ppc; |
506 | *name = luaF_getlocalname(p, reg + 1, pc); | 508 | *name = luaF_getlocalname(p, reg + 1, pc); |
507 | if (*name) /* is a local? */ | 509 | if (*name) /* is a local? */ |
508 | return "local"; | 510 | return strlocal; |
509 | /* else try symbolic execution */ | 511 | /* else try symbolic execution */ |
510 | *ppc = pc = findsetreg(p, pc, reg); | 512 | *ppc = pc = findsetreg(p, pc, reg); |
511 | if (pc != -1) { /* could find instruction? */ | 513 | if (pc != -1) { /* could find instruction? */ |
@@ -520,7 +522,7 @@ static const char *basicgetobjname (const Proto *p, int *ppc, int reg, | |||
520 | } | 522 | } |
521 | case OP_GETUPVAL: { | 523 | case OP_GETUPVAL: { |
522 | *name = upvalname(p, GETARG_B(i)); | 524 | *name = upvalname(p, GETARG_B(i)); |
523 | return "upvalue"; | 525 | return strupval; |
524 | } | 526 | } |
525 | case OP_LOADK: return kname(p, GETARG_Bx(i), name); | 527 | case OP_LOADK: return kname(p, GETARG_Bx(i), name); |
526 | case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name); | 528 | case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name); |
@@ -550,8 +552,13 @@ static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) { | |||
550 | const char *name; /* name of indexed variable */ | 552 | const char *name; /* name of indexed variable */ |
551 | if (isup) /* is 't' an upvalue? */ | 553 | if (isup) /* is 't' an upvalue? */ |
552 | name = upvalname(p, t); | 554 | name = upvalname(p, t); |
553 | else /* 't' is a register */ | 555 | else { /* 't' is a register */ |
554 | basicgetobjname(p, &pc, t, &name); | 556 | const char *what = basicgetobjname(p, &pc, t, &name); |
557 | /* 'name' must be the name of a local variable (at the current | ||
558 | level or an upvalue) */ | ||
559 | if (what != strlocal && what != strupval) | ||
560 | name = NULL; /* cannot be the variable _ENV */ | ||
561 | } | ||
555 | return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; | 562 | return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; |
556 | } | 563 | } |
557 | 564 | ||
@@ -698,7 +705,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o, | |||
698 | for (i = 0; i < c->nupvalues; i++) { | 705 | for (i = 0; i < c->nupvalues; i++) { |
699 | if (c->upvals[i]->v.p == o) { | 706 | if (c->upvals[i]->v.p == o) { |
700 | *name = upvalname(c->p, i); | 707 | *name = upvalname(c->p, i); |
701 | return "upvalue"; | 708 | return strupval; |
702 | } | 709 | } |
703 | } | 710 | } |
704 | return NULL; | 711 | return NULL; |
@@ -832,6 +839,10 @@ l_noret luaG_errormsg (lua_State *L) { | |||
832 | L->top.p++; /* assume EXTRA_STACK */ | 839 | L->top.p++; /* assume EXTRA_STACK */ |
833 | luaD_callnoyield(L, L->top.p - 2, 1); /* call it */ | 840 | luaD_callnoyield(L, L->top.p - 2, 1); /* call it */ |
834 | } | 841 | } |
842 | if (ttisnil(s2v(L->top.p - 1))) { /* error object is nil? */ | ||
843 | /* change it to a proper message */ | ||
844 | setsvalue2s(L, L->top.p - 1, luaS_newliteral(L, "<no error object>")); | ||
845 | } | ||
835 | luaD_throw(L, LUA_ERRRUN); | 846 | luaD_throw(L, LUA_ERRRUN); |
836 | } | 847 | } |
837 | 848 | ||
@@ -102,24 +102,13 @@ struct lua_longjmp { | |||
102 | 102 | ||
103 | 103 | ||
104 | void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop) { | 104 | void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop) { |
105 | switch (errcode) { | 105 | if (errcode == LUA_ERRMEM) { /* memory error? */ |
106 | case LUA_ERRMEM: { /* memory error? */ | 106 | setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ |
107 | setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ | 107 | } |
108 | break; | 108 | else { |
109 | } | 109 | lua_assert(errorstatus(errcode)); /* must be a real error */ |
110 | case LUA_ERRERR: { | 110 | lua_assert(!ttisnil(s2v(L->top.p - 1))); /* with a non-nil object */ |
111 | setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); | 111 | setobjs2s(L, oldtop, L->top.p - 1); /* move it to 'oldtop' */ |
112 | break; | ||
113 | } | ||
114 | default: { | ||
115 | lua_assert(errorstatus(errcode)); /* must be a real error */ | ||
116 | if (!ttisnil(s2v(L->top.p - 1))) { /* error object is not nil? */ | ||
117 | setobjs2s(L, oldtop, L->top.p - 1); /* move it to 'oldtop' */ | ||
118 | } | ||
119 | else /* change it to a proper message */ | ||
120 | setsvalue2s(L, oldtop, luaS_newliteral(L, "<error object is nil>")); | ||
121 | break; | ||
122 | } | ||
123 | } | 112 | } |
124 | L->top.p = oldtop + 1; /* top goes back to old top plus error object */ | 113 | L->top.p = oldtop + 1; /* top goes back to old top plus error object */ |
125 | } | 114 | } |
@@ -190,6 +179,15 @@ TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | |||
190 | #define ERRORSTACKSIZE (MAXSTACK + STACKERRSPACE) | 179 | #define ERRORSTACKSIZE (MAXSTACK + STACKERRSPACE) |
191 | 180 | ||
192 | 181 | ||
182 | /* raise an error while running the message handler */ | ||
183 | l_noret luaD_errerr (lua_State *L) { | ||
184 | TString *msg = luaS_newliteral(L, "error in error handling"); | ||
185 | setsvalue2s(L, L->top.p, msg); | ||
186 | L->top.p++; /* assume EXTRA_STACK */ | ||
187 | luaD_throw(L, LUA_ERRERR); | ||
188 | } | ||
189 | |||
190 | |||
193 | /* | 191 | /* |
194 | ** In ISO C, any pointer use after the pointer has been deallocated is | 192 | ** In ISO C, any pointer use after the pointer has been deallocated is |
195 | ** undefined behavior. So, before a stack reallocation, all pointers | 193 | ** undefined behavior. So, before a stack reallocation, all pointers |
@@ -317,7 +315,7 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) { | |||
317 | a stack error; cannot grow further than that. */ | 315 | a stack error; cannot grow further than that. */ |
318 | lua_assert(stacksize(L) == ERRORSTACKSIZE); | 316 | lua_assert(stacksize(L) == ERRORSTACKSIZE); |
319 | if (raiseerror) | 317 | if (raiseerror) |
320 | luaD_throw(L, LUA_ERRERR); /* error inside message handler */ | 318 | luaD_errerr(L); /* error inside message handler */ |
321 | return 0; /* if not 'raiseerror', just signal it */ | 319 | return 0; /* if not 'raiseerror', just signal it */ |
322 | } | 320 | } |
323 | else if (n < MAXSTACK) { /* avoids arithmetic overflows */ | 321 | else if (n < MAXSTACK) { /* avoids arithmetic overflows */ |
@@ -67,6 +67,7 @@ | |||
67 | /* type of protected functions, to be ran by 'runprotected' */ | 67 | /* type of protected functions, to be ran by 'runprotected' */ |
68 | typedef void (*Pfunc) (lua_State *L, void *ud); | 68 | typedef void (*Pfunc) (lua_State *L, void *ud); |
69 | 69 | ||
70 | LUAI_FUNC l_noret luaD_errerr (lua_State *L); | ||
70 | LUAI_FUNC void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop); | 71 | LUAI_FUNC void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop); |
71 | LUAI_FUNC TStatus luaD_protectedparser (lua_State *L, ZIO *z, | 72 | LUAI_FUNC TStatus luaD_protectedparser (lua_State *L, ZIO *z, |
72 | const char *name, | 73 | const char *name, |
@@ -253,16 +253,19 @@ static void dumpFunction (DumpState *D, const Proto *f) { | |||
253 | } | 253 | } |
254 | 254 | ||
255 | 255 | ||
256 | #define dumpNumInfo(D, tvar, value) \ | ||
257 | { tvar i = value; dumpByte(D, sizeof(tvar)); dumpVar(D, i); } | ||
258 | |||
259 | |||
256 | static void dumpHeader (DumpState *D) { | 260 | static void dumpHeader (DumpState *D) { |
257 | dumpLiteral(D, LUA_SIGNATURE); | 261 | dumpLiteral(D, LUA_SIGNATURE); |
258 | dumpByte(D, LUAC_VERSION); | 262 | dumpByte(D, LUAC_VERSION); |
259 | dumpByte(D, LUAC_FORMAT); | 263 | dumpByte(D, LUAC_FORMAT); |
260 | dumpLiteral(D, LUAC_DATA); | 264 | dumpLiteral(D, LUAC_DATA); |
261 | dumpByte(D, sizeof(Instruction)); | 265 | dumpNumInfo(D, int, LUAC_INT); |
262 | dumpByte(D, sizeof(lua_Integer)); | 266 | dumpNumInfo(D, Instruction, LUAC_INST); |
263 | dumpByte(D, sizeof(lua_Number)); | 267 | dumpNumInfo(D, lua_Integer, LUAC_INT); |
264 | dumpInteger(D, LUAC_INT); | 268 | dumpNumInfo(D, lua_Number, LUAC_NUM); |
265 | dumpNumber(D, LUAC_NUM); | ||
266 | } | 269 | } |
267 | 270 | ||
268 | 271 | ||
@@ -497,10 +497,10 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
497 | hasclears = 1; /* table will have to be cleared */ | 497 | hasclears = 1; /* table will have to be cleared */ |
498 | } | 498 | } |
499 | } | 499 | } |
500 | if (g->gcstate == GCSatomic && hasclears) | 500 | if (g->gcstate == GCSpropagate) |
501 | linkgclist(h, g->weak); /* has to be cleared later */ | ||
502 | else | ||
503 | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ | 501 | linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ |
502 | else if (hasclears) | ||
503 | linkgclist(h, g->weak); /* has to be cleared later */ | ||
504 | } | 504 | } |
505 | 505 | ||
506 | 506 | ||
@@ -132,7 +132,7 @@ void luaE_checkcstack (lua_State *L) { | |||
132 | if (getCcalls(L) == LUAI_MAXCCALLS) | 132 | if (getCcalls(L) == LUAI_MAXCCALLS) |
133 | luaG_runerror(L, "C stack overflow"); | 133 | luaG_runerror(L, "C stack overflow"); |
134 | else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) | 134 | else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) |
135 | luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ | 135 | luaD_errerr(L); /* error while handling stack error */ |
136 | } | 136 | } |
137 | 137 | ||
138 | 138 | ||
@@ -143,25 +143,29 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) { | |||
143 | } | 143 | } |
144 | 144 | ||
145 | 145 | ||
146 | static void resetCI (lua_State *L) { | ||
147 | CallInfo *ci = L->ci = &L->base_ci; | ||
148 | ci->func.p = L->stack.p; | ||
149 | setnilvalue(s2v(ci->func.p)); /* 'function' entry for basic 'ci' */ | ||
150 | ci->top.p = ci->func.p + 1 + LUA_MINSTACK; /* +1 for 'function' entry */ | ||
151 | ci->u.c.k = NULL; | ||
152 | ci->callstatus = CIST_C; | ||
153 | L->status = LUA_OK; | ||
154 | L->errfunc = 0; /* stack unwind can "throw away" the error function */ | ||
155 | } | ||
156 | |||
157 | |||
146 | static void stack_init (lua_State *L1, lua_State *L) { | 158 | static void stack_init (lua_State *L1, lua_State *L) { |
147 | int i; CallInfo *ci; | 159 | int i; |
148 | /* initialize stack array */ | 160 | /* initialize stack array */ |
149 | L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); | 161 | L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); |
150 | L1->tbclist.p = L1->stack.p; | 162 | L1->tbclist.p = L1->stack.p; |
151 | for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) | 163 | for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) |
152 | setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */ | 164 | setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */ |
153 | L1->top.p = L1->stack.p; | ||
154 | L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE; | 165 | L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE; |
155 | /* initialize first ci */ | 166 | /* initialize first ci */ |
156 | ci = &L1->base_ci; | 167 | resetCI(L1); |
157 | ci->next = ci->previous = NULL; | 168 | L1->top.p = L1->stack.p + 1; /* +1 for 'function' entry */ |
158 | ci->callstatus = CIST_C; | ||
159 | ci->func.p = L1->top.p; | ||
160 | ci->u.c.k = NULL; | ||
161 | setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */ | ||
162 | L1->top.p++; | ||
163 | ci->top.p = L1->top.p + LUA_MINSTACK; | ||
164 | L1->ci = ci; | ||
165 | } | 169 | } |
166 | 170 | ||
167 | 171 | ||
@@ -235,6 +239,7 @@ static void preinit_thread (lua_State *L, global_State *g) { | |||
235 | L->status = LUA_OK; | 239 | L->status = LUA_OK; |
236 | L->errfunc = 0; | 240 | L->errfunc = 0; |
237 | L->oldpc = 0; | 241 | L->oldpc = 0; |
242 | L->base_ci.previous = L->base_ci.next = NULL; | ||
238 | } | 243 | } |
239 | 244 | ||
240 | 245 | ||
@@ -252,8 +257,9 @@ static void close_state (lua_State *L) { | |||
252 | if (!completestate(g)) /* closing a partially built state? */ | 257 | if (!completestate(g)) /* closing a partially built state? */ |
253 | luaC_freeallobjects(L); /* just collect its objects */ | 258 | luaC_freeallobjects(L); /* just collect its objects */ |
254 | else { /* closing a fully built state */ | 259 | else { /* closing a fully built state */ |
255 | L->ci = &L->base_ci; /* unwind CallInfo list */ | 260 | resetCI(L); |
256 | luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ | 261 | luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ |
262 | L->top.p = L->stack.p + 1; /* empty the stack to run finalizers */ | ||
257 | luaC_freeallobjects(L); /* collect all objects */ | 263 | luaC_freeallobjects(L); /* collect all objects */ |
258 | luai_userstateclose(L); | 264 | luai_userstateclose(L); |
259 | } | 265 | } |
@@ -302,20 +308,15 @@ void luaE_freethread (lua_State *L, lua_State *L1) { | |||
302 | 308 | ||
303 | 309 | ||
304 | TStatus luaE_resetthread (lua_State *L, TStatus status) { | 310 | TStatus luaE_resetthread (lua_State *L, TStatus status) { |
305 | CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */ | 311 | resetCI(L); |
306 | setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */ | ||
307 | ci->func.p = L->stack.p; | ||
308 | ci->callstatus = CIST_C; | ||
309 | if (status == LUA_YIELD) | 312 | if (status == LUA_YIELD) |
310 | status = LUA_OK; | 313 | status = LUA_OK; |
311 | L->status = LUA_OK; /* so it can run __close metamethods */ | ||
312 | status = luaD_closeprotected(L, 1, status); | 314 | status = luaD_closeprotected(L, 1, status); |
313 | if (status != LUA_OK) /* errors? */ | 315 | if (status != LUA_OK) /* errors? */ |
314 | luaD_seterrorobj(L, status, L->stack.p + 1); | 316 | luaD_seterrorobj(L, status, L->stack.p + 1); |
315 | else | 317 | else |
316 | L->top.p = L->stack.p + 1; | 318 | L->top.p = L->stack.p + 1; |
317 | ci->top.p = L->top.p + LUA_MINSTACK; | 319 | luaD_reallocstack(L, cast_int(L->ci->top.p - L->stack.p), 0); |
318 | luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0); | ||
319 | return status; | 320 | return status; |
320 | } | 321 | } |
321 | 322 | ||
@@ -872,6 +872,28 @@ void lua_printstack (lua_State *L) { | |||
872 | } | 872 | } |
873 | 873 | ||
874 | 874 | ||
875 | int lua_printallstack (lua_State *L) { | ||
876 | StkId p; | ||
877 | int i = 1; | ||
878 | CallInfo *ci = &L->base_ci; | ||
879 | printf("stack: >>\n"); | ||
880 | for (p = L->stack.p; p < L->top.p; p++) { | ||
881 | if (ci != NULL && p == ci->func.p) { | ||
882 | printf(" ---\n"); | ||
883 | if (ci == L->ci) | ||
884 | ci = NULL; /* printed last frame */ | ||
885 | else | ||
886 | ci = ci->next; | ||
887 | } | ||
888 | printf("%3d: ", i++); | ||
889 | lua_printvalue(s2v(p)); | ||
890 | printf("\n"); | ||
891 | } | ||
892 | printf("<<\n"); | ||
893 | return 0; | ||
894 | } | ||
895 | |||
896 | |||
875 | static int get_limits (lua_State *L) { | 897 | static int get_limits (lua_State *L) { |
876 | lua_createtable(L, 0, 5); | 898 | lua_createtable(L, 0, 5); |
877 | setnameval(L, "IS32INT", LUAI_IS32INT); | 899 | setnameval(L, "IS32INT", LUAI_IS32INT); |
@@ -982,7 +1004,7 @@ static int gc_printobj (lua_State *L) { | |||
982 | } | 1004 | } |
983 | 1005 | ||
984 | 1006 | ||
985 | static const char *statenames[] = { | 1007 | static const char *const statenames[] = { |
986 | "propagate", "enteratomic", "atomic", "sweepallgc", "sweepfinobj", | 1008 | "propagate", "enteratomic", "atomic", "sweepallgc", "sweepfinobj", |
987 | "sweeptobefnz", "sweepend", "callfin", "pause", ""}; | 1009 | "sweeptobefnz", "sweepend", "callfin", "pause", ""}; |
988 | 1010 | ||
@@ -2102,6 +2124,7 @@ static const struct luaL_Reg tests_funcs[] = { | |||
2102 | {"limits", get_limits}, | 2124 | {"limits", get_limits}, |
2103 | {"listcode", listcode}, | 2125 | {"listcode", listcode}, |
2104 | {"printcode", printcode}, | 2126 | {"printcode", printcode}, |
2127 | {"printallstack", lua_printallstack}, | ||
2105 | {"listk", listk}, | 2128 | {"listk", listk}, |
2106 | {"listabslineinfo", listabslineinfo}, | 2129 | {"listabslineinfo", listabslineinfo}, |
2107 | {"listlocals", listlocals}, | 2130 | {"listlocals", listlocals}, |
@@ -94,6 +94,7 @@ LUAI_FUNC void lua_printvalue (struct TValue *v); | |||
94 | ** Function to print the stack | 94 | ** Function to print the stack |
95 | */ | 95 | */ |
96 | LUAI_FUNC void lua_printstack (lua_State *L); | 96 | LUAI_FUNC void lua_printstack (lua_State *L); |
97 | LUAI_FUNC int lua_printallstack (lua_State *L); | ||
97 | 98 | ||
98 | 99 | ||
99 | /* test for lock/unlock */ | 100 | /* test for lock/unlock */ |
@@ -345,13 +345,29 @@ static void checkliteral (LoadState *S, const char *s, const char *msg) { | |||
345 | } | 345 | } |
346 | 346 | ||
347 | 347 | ||
348 | static void fchecksize (LoadState *S, size_t size, const char *tname) { | 348 | static l_noret numerror (LoadState *S, const char *what, const char *tname) { |
349 | if (loadByte(S) != size) | 349 | const char *msg = luaO_pushfstring(S->L, "%s %s mismatch", tname, what); |
350 | error(S, luaO_pushfstring(S->L, "%s size mismatch", tname)); | 350 | error(S, msg); |
351 | } | 351 | } |
352 | 352 | ||
353 | 353 | ||
354 | #define checksize(S,t) fchecksize(S,sizeof(t),#t) | 354 | static void checknumsize (LoadState *S, int size, const char *tname) { |
355 | if (size != loadByte(S)) | ||
356 | numerror(S, "size", tname); | ||
357 | } | ||
358 | |||
359 | |||
360 | static void checknumformat (LoadState *S, int eq, const char *tname) { | ||
361 | if (!eq) | ||
362 | numerror(S, "format", tname); | ||
363 | } | ||
364 | |||
365 | |||
366 | #define checknum(S,tvar,value,tname) \ | ||
367 | { tvar i; checknumsize(S, sizeof(i), tname); \ | ||
368 | loadVar(S, i); \ | ||
369 | checknumformat(S, i == value, tname); } | ||
370 | |||
355 | 371 | ||
356 | static void checkHeader (LoadState *S) { | 372 | static void checkHeader (LoadState *S) { |
357 | /* skip 1st char (already read and checked) */ | 373 | /* skip 1st char (already read and checked) */ |
@@ -361,13 +377,10 @@ static void checkHeader (LoadState *S) { | |||
361 | if (loadByte(S) != LUAC_FORMAT) | 377 | if (loadByte(S) != LUAC_FORMAT) |
362 | error(S, "format mismatch"); | 378 | error(S, "format mismatch"); |
363 | checkliteral(S, LUAC_DATA, "corrupted chunk"); | 379 | checkliteral(S, LUAC_DATA, "corrupted chunk"); |
364 | checksize(S, Instruction); | 380 | checknum(S, int, LUAC_INT, "int"); |
365 | checksize(S, lua_Integer); | 381 | checknum(S, Instruction, LUAC_INST, "instruction"); |
366 | checksize(S, lua_Number); | 382 | checknum(S, lua_Integer, LUAC_INT, "Lua integer"); |
367 | if (loadInteger(S) != LUAC_INT) | 383 | checknum(S, lua_Number, LUAC_NUM, "Lua number"); |
368 | error(S, "integer format mismatch"); | ||
369 | if (loadNumber(S) != LUAC_NUM) | ||
370 | error(S, "float format mismatch"); | ||
371 | } | 384 | } |
372 | 385 | ||
373 | 386 | ||
@@ -398,7 +411,8 @@ LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) { | |||
398 | cl->p = luaF_newproto(L); | 411 | cl->p = luaF_newproto(L); |
399 | luaC_objbarrier(L, cl, cl->p); | 412 | luaC_objbarrier(L, cl, cl->p); |
400 | loadFunction(&S, cl->p); | 413 | loadFunction(&S, cl->p); |
401 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); | 414 | if (cl->nupvalues != cl->p->sizeupvalues) |
415 | error(&S, "corrupted chunk"); | ||
402 | luai_verifycode(L, cl->p); | 416 | luai_verifycode(L, cl->p); |
403 | L->top.p--; /* pop table */ | 417 | L->top.p--; /* pop table */ |
404 | return cl; | 418 | return cl; |
@@ -17,8 +17,9 @@ | |||
17 | /* data to catch conversion errors */ | 17 | /* data to catch conversion errors */ |
18 | #define LUAC_DATA "\x19\x93\r\n\x1a\n" | 18 | #define LUAC_DATA "\x19\x93\r\n\x1a\n" |
19 | 19 | ||
20 | #define LUAC_INT 0x5678 | 20 | #define LUAC_INT -0x5678 |
21 | #define LUAC_NUM cast_num(370.5) | 21 | #define LUAC_INST 0x12345678 |
22 | #define LUAC_NUM cast_num(-370.5) | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | ** Encode major-minor version in one byte, one nibble for each | 25 | ** Encode major-minor version in one byte, one nibble for each |
@@ -325,6 +325,11 @@ lu_byte luaV_finishget (lua_State *L, const TValue *t, TValue *key, | |||
325 | 325 | ||
326 | /* | 326 | /* |
327 | ** Finish a table assignment 't[key] = val'. | 327 | ** Finish a table assignment 't[key] = val'. |
328 | ** About anchoring the table before the call to 'luaH_finishset': | ||
329 | ** This call may trigger an emergency collection. When loop>0, | ||
330 | ** the table being acessed is a field in some metatable. If this | ||
331 | ** metatable is weak and the table is not anchored, this collection | ||
332 | ** could collect that table while it is being updated. | ||
328 | */ | 333 | */ |
329 | void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | 334 | void luaV_finishset (lua_State *L, const TValue *t, TValue *key, |
330 | TValue *val, int hres) { | 335 | TValue *val, int hres) { |
@@ -335,7 +340,10 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
335 | Table *h = hvalue(t); /* save 't' table */ | 340 | Table *h = hvalue(t); /* save 't' table */ |
336 | tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ | 341 | tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ |
337 | if (tm == NULL) { /* no metamethod? */ | 342 | if (tm == NULL) { /* no metamethod? */ |
343 | sethvalue2s(L, L->top.p, h); /* anchor 't' */ | ||
344 | L->top.p++; /* assume EXTRA_STACK */ | ||
338 | luaH_finishset(L, h, key, val, hres); /* set new value */ | 345 | luaH_finishset(L, h, key, val, hres); /* set new value */ |
346 | L->top.p--; | ||
339 | invalidateTMcache(h); | 347 | invalidateTMcache(h); |
340 | luaC_barrierback(L, obj2gco(h), val); | 348 | luaC_barrierback(L, obj2gco(h), val); |
341 | return; | 349 | return; |
@@ -354,8 +362,10 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
354 | } | 362 | } |
355 | t = tm; /* else repeat assignment over 'tm' */ | 363 | t = tm; /* else repeat assignment over 'tm' */ |
356 | luaV_fastset(t, key, val, hres, luaH_pset); | 364 | luaV_fastset(t, key, val, hres, luaH_pset); |
357 | if (hres == HOK) | 365 | if (hres == HOK) { |
366 | luaV_finishfastset(L, t, val); | ||
358 | return; /* done */ | 367 | return; /* done */ |
368 | } | ||
359 | /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ | 369 | /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ |
360 | } | 370 | } |
361 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); | 371 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); |
diff --git a/manual/manual.of b/manual/manual.of index b34e1e9c..c1a9c138 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -2222,10 +2222,10 @@ f(3, 4, 5) a=3, b=4 | |||
2222 | f(r(), 10) a=1, b=10 | 2222 | f(r(), 10) a=1, b=10 |
2223 | f(r()) a=1, b=2 | 2223 | f(r()) a=1, b=2 |
2224 | 2224 | ||
2225 | g(3) a=3, b=nil, ... --> (nothing) | 2225 | g(3) a=3, b=nil, ... -> (nothing) |
2226 | g(3, 4) a=3, b=4, ... --> (nothing) | 2226 | g(3, 4) a=3, b=4, ... -> (nothing) |
2227 | g(3, 4, 5, 8) a=3, b=4, ... --> 5 8 | 2227 | g(3, 4, 5, 8) a=3, b=4, ... -> 5 8 |
2228 | g(5, r()) a=5, b=1, ... --> 2 3 | 2228 | g(5, r()) a=5, b=1, ... -> 2 3 |
2229 | } | 2229 | } |
2230 | 2230 | ||
2231 | Results are returned using the @Rw{return} statement @see{control}. | 2231 | Results are returned using the @Rw{return} statement @see{control}. |
@@ -6230,15 +6230,17 @@ Returns the name of the type of the value at the given index. | |||
6230 | @APIEntry{void luaL_unref (lua_State *L, int t, int ref);| | 6230 | @APIEntry{void luaL_unref (lua_State *L, int t, int ref);| |
6231 | @apii{0,0,-} | 6231 | @apii{0,0,-} |
6232 | 6232 | ||
6233 | Releases the reference @id{ref} from the table at index @id{t} | 6233 | Releases a reference @see{luaL_ref}. |
6234 | @seeC{luaL_ref}. | 6234 | The integer @id{ref} must be either |
6235 | The entry is removed from the table, | 6235 | @Lid{LUA_NOREF}, @Lid{LUA_REFNIL}, |
6236 | or a reference previously returned by @Lid{luaL_ref} | ||
6237 | and not already released. | ||
6238 | If @id{ref} is either @Lid{LUA_NOREF} or @Lid{LUA_REFNIL} | ||
6239 | this function does nothing. | ||
6240 | Otherwise, the entry is removed from the table, | ||
6236 | so that the referred object can be collected and | 6241 | so that the referred object can be collected and |
6237 | the reference @id{ref} can be used again by @Lid{luaL_ref}. | 6242 | the reference @id{ref} can be used again by @Lid{luaL_ref}. |
6238 | 6243 | ||
6239 | If @id{ref} is @Lid{LUA_NOREF} or @Lid{LUA_REFNIL}, | ||
6240 | @Lid{luaL_unref} does nothing. | ||
6241 | |||
6242 | } | 6244 | } |
6243 | 6245 | ||
6244 | @APIEntry{void luaL_where (lua_State *L, int lvl);| | 6246 | @APIEntry{void luaL_where (lua_State *L, int lvl);| |
@@ -7477,25 +7479,25 @@ then there is no replacement | |||
7477 | Here are some examples: | 7479 | Here are some examples: |
7478 | @verbatim{ | 7480 | @verbatim{ |
7479 | x = string.gsub("hello world", "(%w+)", "%1 %1") | 7481 | x = string.gsub("hello world", "(%w+)", "%1 %1") |
7480 | --> x="hello hello world world" | 7482 | -- x="hello hello world world" |
7481 | 7483 | ||
7482 | x = string.gsub("hello world", "%w+", "%0 %0", 1) | 7484 | x = string.gsub("hello world", "%w+", "%0 %0", 1) |
7483 | --> x="hello hello world" | 7485 | -- x="hello hello world" |
7484 | 7486 | ||
7485 | x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") | 7487 | x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") |
7486 | --> x="world hello Lua from" | 7488 | -- x="world hello Lua from" |
7487 | 7489 | ||
7488 | x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) | 7490 | x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) |
7489 | --> x="home = /home/roberto, user = roberto" | 7491 | -- x="home = /home/roberto, user = roberto" |
7490 | 7492 | ||
7491 | x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) | 7493 | x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) |
7492 | return load(s)() | 7494 | return load(s)() |
7493 | end) | 7495 | end) |
7494 | --> x="4+5 = 9" | 7496 | -- x="4+5 = 9" |
7495 | 7497 | ||
7496 | local t = {name="lua", version="5.4"} | 7498 | local t = {name="lua", version="5.4"} |
7497 | x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) | 7499 | x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) |
7498 | --> x="lua-5.4.tar.gz" | 7500 | -- x="lua-5.4.tar.gz" |
7499 | } | 7501 | } |
7500 | 7502 | ||
7501 | } | 7503 | } |
@@ -9299,15 +9301,21 @@ the interpreter waits for its completion | |||
9299 | by issuing a different prompt. | 9301 | by issuing a different prompt. |
9300 | 9302 | ||
9301 | Note that, as each complete line is read as a new chunk, | 9303 | Note that, as each complete line is read as a new chunk, |
9302 | local variables do not outlive lines: | 9304 | local variables do not outlive lines. |
9305 | To steer clear of confusion, | ||
9306 | the interpreter gives a warning if a line starts with the | ||
9307 | reserved word @Rw{local}: | ||
9303 | @verbatim{ | 9308 | @verbatim{ |
9304 | > x = 20 | 9309 | > x = 20 -- global 'x' |
9305 | > local x = 10; print(x) --> 10 | 9310 | > local x = 10; print(x) |
9306 | > print(x) --> 20 -- global 'x' | 9311 | --> warning: locals do not survive across lines in interactive mode |
9307 | > do -- incomplete line | 9312 | --> 10 |
9313 | > print(x) -- back to global 'x' | ||
9314 | --> 20 | ||
9315 | > do -- incomplete chunk | ||
9308 | >> local x = 10; print(x) -- '>>' prompts for line completion | 9316 | >> local x = 10; print(x) -- '>>' prompts for line completion |
9309 | >> print(x) | 9317 | >> print(x) |
9310 | >> end -- line completed; Lua will run it as a single chunk | 9318 | >> end -- chunk completed |
9311 | --> 10 | 9319 | --> 10 |
9312 | --> 10 | 9320 | --> 10 |
9313 | } | 9321 | } |
diff --git a/testes/all.lua b/testes/all.lua index 4ffa9efe..5c7ebfa5 100644 --- a/testes/all.lua +++ b/testes/all.lua | |||
@@ -1,6 +1,6 @@ | |||
1 | #!../lua | 1 | #!../lua |
2 | -- $Id: testes/all.lua $ | 2 | -- $Id: testes/all.lua $ |
3 | -- See Copyright Notice at the end of this file | 3 | -- See Copyright Notice in file lua.h |
4 | 4 | ||
5 | 5 | ||
6 | local version = "Lua 5.5" | 6 | local version = "Lua 5.5" |
@@ -182,6 +182,7 @@ dofile('nextvar.lua') | |||
182 | dofile('pm.lua') | 182 | dofile('pm.lua') |
183 | dofile('utf8.lua') | 183 | dofile('utf8.lua') |
184 | dofile('api.lua') | 184 | dofile('api.lua') |
185 | dofile('memerr.lua') | ||
185 | assert(dofile('events.lua') == 12) | 186 | assert(dofile('events.lua') == 12) |
186 | dofile('vararg.lua') | 187 | dofile('vararg.lua') |
187 | dofile('closure.lua') | 188 | dofile('closure.lua') |
@@ -282,30 +283,3 @@ end | |||
282 | 283 | ||
283 | print("final OK !!!") | 284 | print("final OK !!!") |
284 | 285 | ||
285 | |||
286 | |||
287 | --[[ | ||
288 | ***************************************************************************** | ||
289 | * Copyright (C) 1994-2016 Lua.org, PUC-Rio. | ||
290 | * | ||
291 | * Permission is hereby granted, free of charge, to any person obtaining | ||
292 | * a copy of this software and associated documentation files (the | ||
293 | * "Software"), to deal in the Software without restriction, including | ||
294 | * without limitation the rights to use, copy, modify, merge, publish, | ||
295 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
296 | * permit persons to whom the Software is furnished to do so, subject to | ||
297 | * the following conditions: | ||
298 | * | ||
299 | * The above copyright notice and this permission notice shall be | ||
300 | * included in all copies or substantial portions of the Software. | ||
301 | * | ||
302 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
303 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
304 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
305 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
306 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
307 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
308 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
309 | ***************************************************************************** | ||
310 | ]] | ||
311 | |||
diff --git a/testes/api.lua b/testes/api.lua index 21f703fd..49e3f9b9 100644 --- a/testes/api.lua +++ b/testes/api.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/api.lua $ | 1 | -- $Id: testes/api.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | if T==nil then | 4 | if T==nil then |
5 | (Message or print)('\n >>> testC not active: skipping API tests <<<\n') | 5 | (Message or print)('\n >>> testC not active: skipping API tests <<<\n') |
@@ -11,9 +11,6 @@ local debug = require "debug" | |||
11 | local pack = table.pack | 11 | local pack = table.pack |
12 | 12 | ||
13 | 13 | ||
14 | -- standard error message for memory errors | ||
15 | local MEMERRMSG = "not enough memory" | ||
16 | |||
17 | local function tcheck (t1, t2) | 14 | local function tcheck (t1, t2) |
18 | assert(t1.n == (t2.n or #t2) + 1) | 15 | assert(t1.n == (t2.n or #t2) + 1) |
19 | for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end | 16 | for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end |
@@ -432,11 +429,6 @@ do | |||
432 | "bad argument #4 (string expected, got no value)") | 429 | "bad argument #4 (string expected, got no value)") |
433 | 430 | ||
434 | 431 | ||
435 | -- memory error | ||
436 | T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k) | ||
437 | assert(T.checkpanic("newuserdata 20000") == MEMERRMSG) | ||
438 | T.totalmem(0) -- restore high limit | ||
439 | |||
440 | -- memory error + thread status | 432 | -- memory error + thread status |
441 | local x = T.checkpanic( | 433 | local x = T.checkpanic( |
442 | [[ alloccount 0 # force a memory error in next line | 434 | [[ alloccount 0 # force a memory error in next line |
@@ -1306,241 +1298,6 @@ do | |||
1306 | end | 1298 | end |
1307 | 1299 | ||
1308 | 1300 | ||
1309 | --[[ | ||
1310 | ** {================================================================== | ||
1311 | ** Testing memory limits | ||
1312 | ** =================================================================== | ||
1313 | --]] | ||
1314 | |||
1315 | print("memory-allocation errors") | ||
1316 | |||
1317 | checkerr("block too big", T.newuserdata, math.maxinteger) | ||
1318 | collectgarbage() | ||
1319 | local f = load"local a={}; for i=1,100000 do a[i]=i end" | ||
1320 | T.alloccount(10) | ||
1321 | checkerr(MEMERRMSG, f) | ||
1322 | T.alloccount() -- remove limit | ||
1323 | |||
1324 | |||
1325 | -- test memory errors; increase limit for maximum memory by steps, | ||
1326 | -- o that we get memory errors in all allocations of a given | ||
1327 | -- task, until there is enough memory to complete the task without | ||
1328 | -- errors. | ||
1329 | local function testbytes (s, f) | ||
1330 | collectgarbage() | ||
1331 | local M = T.totalmem() | ||
1332 | local oldM = M | ||
1333 | local a,b = nil | ||
1334 | while true do | ||
1335 | collectgarbage(); collectgarbage() | ||
1336 | T.totalmem(M) | ||
1337 | a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f) | ||
1338 | T.totalmem(0) -- remove limit | ||
1339 | if a and b == "OK" then break end -- stop when no more errors | ||
1340 | if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error? | ||
1341 | error(a, 0) -- propagate it | ||
1342 | end | ||
1343 | M = M + 7 -- increase memory limit | ||
1344 | end | ||
1345 | print(string.format("minimum memory for %s: %d bytes", s, M - oldM)) | ||
1346 | return a | ||
1347 | end | ||
1348 | |||
1349 | -- test memory errors; increase limit for number of allocations one | ||
1350 | -- by one, so that we get memory errors in all allocations of a given | ||
1351 | -- task, until there is enough allocations to complete the task without | ||
1352 | -- errors. | ||
1353 | |||
1354 | local function testalloc (s, f) | ||
1355 | collectgarbage() | ||
1356 | local M = 0 | ||
1357 | local a,b = nil | ||
1358 | while true do | ||
1359 | collectgarbage(); collectgarbage() | ||
1360 | T.alloccount(M) | ||
1361 | a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f) | ||
1362 | T.alloccount() -- remove limit | ||
1363 | if a and b == "OK" then break end -- stop when no more errors | ||
1364 | if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error? | ||
1365 | error(a, 0) -- propagate it | ||
1366 | end | ||
1367 | M = M + 1 -- increase allocation limit | ||
1368 | end | ||
1369 | print(string.format("minimum allocations for %s: %d allocations", s, M)) | ||
1370 | return a | ||
1371 | end | ||
1372 | |||
1373 | |||
1374 | local function testamem (s, f) | ||
1375 | testalloc(s, f) | ||
1376 | return testbytes(s, f) | ||
1377 | end | ||
1378 | |||
1379 | |||
1380 | -- doing nothing | ||
1381 | b = testamem("doing nothing", function () return 10 end) | ||
1382 | assert(b == 10) | ||
1383 | |||
1384 | -- testing memory errors when creating a new state | ||
1385 | |||
1386 | testamem("state creation", function () | ||
1387 | local st = T.newstate() | ||
1388 | if st then T.closestate(st) end -- close new state | ||
1389 | return st | ||
1390 | end) | ||
1391 | |||
1392 | testamem("empty-table creation", function () | ||
1393 | return {} | ||
1394 | end) | ||
1395 | |||
1396 | testamem("string creation", function () | ||
1397 | return "XXX" .. "YYY" | ||
1398 | end) | ||
1399 | |||
1400 | testamem("coroutine creation", function() | ||
1401 | return coroutine.create(print) | ||
1402 | end) | ||
1403 | |||
1404 | |||
1405 | -- testing to-be-closed variables | ||
1406 | testamem("to-be-closed variables", function() | ||
1407 | local flag | ||
1408 | do | ||
1409 | local x <close> = | ||
1410 | setmetatable({}, {__close = function () flag = true end}) | ||
1411 | flag = false | ||
1412 | local x = {} | ||
1413 | end | ||
1414 | return flag | ||
1415 | end) | ||
1416 | |||
1417 | |||
1418 | -- testing threads | ||
1419 | |||
1420 | -- get main thread from registry | ||
1421 | local mt = T.testC("rawgeti R !M; return 1") | ||
1422 | assert(type(mt) == "thread" and coroutine.running() == mt) | ||
1423 | |||
1424 | |||
1425 | |||
1426 | local function expand (n,s) | ||
1427 | if n==0 then return "" end | ||
1428 | local e = string.rep("=", n) | ||
1429 | return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n", | ||
1430 | e, s, expand(n-1,s), e) | ||
1431 | end | ||
1432 | |||
1433 | G=0; collectgarbage(); a =collectgarbage("count") | ||
1434 | load(expand(20,"G=G+1"))() | ||
1435 | assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1) | ||
1436 | G = nil | ||
1437 | |||
1438 | testamem("running code on new thread", function () | ||
1439 | return T.doonnewstack("local x=1") == 0 -- try to create thread | ||
1440 | end) | ||
1441 | |||
1442 | |||
1443 | -- testing memory x compiler | ||
1444 | |||
1445 | testamem("loadstring", function () | ||
1446 | return load("x=1") -- try to do load a string | ||
1447 | end) | ||
1448 | |||
1449 | |||
1450 | local testprog = [[ | ||
1451 | local function foo () return end | ||
1452 | local t = {"x"} | ||
1453 | AA = "aaa" | ||
1454 | for i = 1, #t do AA = AA .. t[i] end | ||
1455 | return true | ||
1456 | ]] | ||
1457 | |||
1458 | -- testing memory x dofile | ||
1459 | _G.AA = nil | ||
1460 | local t =os.tmpname() | ||
1461 | local f = assert(io.open(t, "w")) | ||
1462 | f:write(testprog) | ||
1463 | f:close() | ||
1464 | testamem("dofile", function () | ||
1465 | local a = loadfile(t) | ||
1466 | return a and a() | ||
1467 | end) | ||
1468 | assert(os.remove(t)) | ||
1469 | assert(_G.AA == "aaax") | ||
1470 | |||
1471 | |||
1472 | -- other generic tests | ||
1473 | |||
1474 | testamem("gsub", function () | ||
1475 | local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end) | ||
1476 | return (a == 'ablo ablo') | ||
1477 | end) | ||
1478 | |||
1479 | testamem("dump/undump", function () | ||
1480 | local a = load(testprog) | ||
1481 | local b = a and string.dump(a) | ||
1482 | a = b and load(b) | ||
1483 | return a and a() | ||
1484 | end) | ||
1485 | |||
1486 | _G.AA = nil | ||
1487 | |||
1488 | local t = os.tmpname() | ||
1489 | testamem("file creation", function () | ||
1490 | local f = assert(io.open(t, 'w')) | ||
1491 | assert (not io.open"nomenaoexistente") | ||
1492 | io.close(f); | ||
1493 | return not loadfile'nomenaoexistente' | ||
1494 | end) | ||
1495 | assert(os.remove(t)) | ||
1496 | |||
1497 | testamem("table creation", function () | ||
1498 | local a, lim = {}, 10 | ||
1499 | for i=1,lim do a[i] = i; a[i..'a'] = {} end | ||
1500 | return (type(a[lim..'a']) == 'table' and a[lim] == lim) | ||
1501 | end) | ||
1502 | |||
1503 | testamem("constructors", function () | ||
1504 | local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5} | ||
1505 | return (type(a) == 'table' and a.e == 5) | ||
1506 | end) | ||
1507 | |||
1508 | local a = 1 | ||
1509 | local close = nil | ||
1510 | testamem("closure creation", function () | ||
1511 | function close (b) | ||
1512 | return function (x) return b + x end | ||
1513 | end | ||
1514 | return (close(2)(4) == 6) | ||
1515 | end) | ||
1516 | |||
1517 | testamem("using coroutines", function () | ||
1518 | local a = coroutine.wrap(function () | ||
1519 | coroutine.yield(string.rep("a", 10)) | ||
1520 | return {} | ||
1521 | end) | ||
1522 | assert(string.len(a()) == 10) | ||
1523 | return a() | ||
1524 | end) | ||
1525 | |||
1526 | do -- auxiliary buffer | ||
1527 | local lim = 100 | ||
1528 | local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end | ||
1529 | testamem("auxiliary buffer", function () | ||
1530 | return (#table.concat(a, ",") == 20*lim + lim - 1) | ||
1531 | end) | ||
1532 | end | ||
1533 | |||
1534 | testamem("growing stack", function () | ||
1535 | local function foo (n) | ||
1536 | if n == 0 then return 1 else return 1 + foo(n - 1) end | ||
1537 | end | ||
1538 | return foo(100) | ||
1539 | end) | ||
1540 | |||
1541 | -- }================================================================== | ||
1542 | |||
1543 | |||
1544 | do -- testing failing in 'lua_checkstack' | 1301 | do -- testing failing in 'lua_checkstack' |
1545 | local res = T.testC([[rawcheckstack 500000; return 1]]) | 1302 | local res = T.testC([[rawcheckstack 500000; return 1]]) |
1546 | assert(res == false) | 1303 | assert(res == false) |
diff --git a/testes/attrib.lua b/testes/attrib.lua index 9054e0b6..d8b6e0f3 100644 --- a/testes/attrib.lua +++ b/testes/attrib.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/attrib.lua $ | 1 | -- $Id: testes/attrib.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print "testing require" | 4 | print "testing require" |
5 | 5 | ||
diff --git a/testes/big.lua b/testes/big.lua index 46fd8466..119caa6c 100644 --- a/testes/big.lua +++ b/testes/big.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/big.lua $ | 1 | -- $Id: testes/big.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | if _soft then | 4 | if _soft then |
5 | return 'a' | 5 | return 'a' |
diff --git a/testes/bitwise.lua b/testes/bitwise.lua index dd0a1a9a..10afff43 100644 --- a/testes/bitwise.lua +++ b/testes/bitwise.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/bitwise.lua $ | 1 | -- $Id: testes/bitwise.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print("testing bitwise operations") | 4 | print("testing bitwise operations") |
5 | 5 | ||
diff --git a/testes/calls.lua b/testes/calls.lua index 31028215..942fad72 100644 --- a/testes/calls.lua +++ b/testes/calls.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/calls.lua $ | 1 | -- $Id: testes/calls.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print("testing functions and calls") | 4 | print("testing functions and calls") |
5 | 5 | ||
@@ -480,15 +480,22 @@ assert((function (a) return a end)() == nil) | |||
480 | 480 | ||
481 | print("testing binary chunks") | 481 | print("testing binary chunks") |
482 | do | 482 | do |
483 | local header = string.pack("c4BBc6BBB", | 483 | local headformat = "c4BBc6BiBI4BjBn" |
484 | "\27Lua", -- signature | 484 | local header = { -- header components |
485 | 0x55, -- version 5.5 (0x55) | 485 | "\27Lua", -- signature |
486 | 0, -- format | 486 | 0x55, -- version 5.5 (0x55) |
487 | "\x19\x93\r\n\x1a\n", -- data | 487 | 0, -- format |
488 | 4, -- size of instruction | 488 | "\x19\x93\r\n\x1a\n", -- a binary string |
489 | string.packsize("j"), -- sizeof(lua integer) | 489 | string.packsize("i"), -- size of an int |
490 | string.packsize("n") -- sizeof(lua number) | 490 | -0x5678, -- an int |
491 | ) | 491 | 4, -- size of an instruction |
492 | 0x12345678, -- an instruction (4 bytes) | ||
493 | string.packsize("j"), -- size of a Lua integer | ||
494 | -0x5678, -- a Lua integer | ||
495 | string.packsize("n"), -- size of a Lua float | ||
496 | -370.5, -- a Lua float | ||
497 | } | ||
498 | |||
492 | local c = string.dump(function () | 499 | local c = string.dump(function () |
493 | local a = 1; local b = 3; | 500 | local a = 1; local b = 3; |
494 | local f = function () return a + b + _ENV.c; end -- upvalues | 501 | local f = function () return a + b + _ENV.c; end -- upvalues |
@@ -500,17 +507,23 @@ do | |||
500 | assert(assert(load(c))() == 10) | 507 | assert(assert(load(c))() == 10) |
501 | 508 | ||
502 | -- check header | 509 | -- check header |
503 | assert(string.sub(c, 1, #header) == header) | 510 | local t = {string.unpack(headformat, c)} |
504 | -- check LUAC_INT and LUAC_NUM | ||
505 | local ci, cn = string.unpack("jn", c, #header + 1) | ||
506 | assert(ci == 0x5678 and cn == 370.5) | ||
507 | |||
508 | -- corrupted header | ||
509 | for i = 1, #header do | 511 | for i = 1, #header do |
512 | assert(t[i] == header[i]) | ||
513 | end | ||
514 | |||
515 | -- Testing corrupted header. | ||
516 | -- A single wrong byte in the head invalidates the chunk, | ||
517 | -- except for the Lua float check. (If numbers are long double, | ||
518 | -- the representation may need padding, and changing that padding | ||
519 | -- will not invalidate the chunk.) | ||
520 | local headlen = string.packsize(headformat) | ||
521 | headlen = headlen - string.packsize("n") -- remove float check | ||
522 | for i = 1, headlen do | ||
510 | local s = string.sub(c, 1, i - 1) .. | 523 | local s = string.sub(c, 1, i - 1) .. |
511 | string.char(string.byte(string.sub(c, i, i)) + 1) .. | 524 | string.char((string.byte(string.sub(c, i, i)) + 1) & 0xFF) .. |
512 | string.sub(c, i + 1, -1) | 525 | string.sub(c, i + 1, -1) |
513 | assert(#s == #c) | 526 | assert(#s == #c and s ~= c) |
514 | assert(not load(s)) | 527 | assert(not load(s)) |
515 | end | 528 | end |
516 | 529 | ||
diff --git a/testes/closure.lua b/testes/closure.lua index 07149ef3..d3b9f621 100644 --- a/testes/closure.lua +++ b/testes/closure.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/closure.lua $ | 1 | -- $Id: testes/closure.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print "testing closures" | 4 | print "testing closures" |
5 | 5 | ||
diff --git a/testes/code.lua b/testes/code.lua index 50ce7392..111717ce 100644 --- a/testes/code.lua +++ b/testes/code.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/code.lua $ | 1 | -- $Id: testes/code.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | if T==nil then | 4 | if T==nil then |
5 | (Message or print)('\n >>> testC not active: skipping opcode tests <<<\n') | 5 | (Message or print)('\n >>> testC not active: skipping opcode tests <<<\n') |
diff --git a/testes/constructs.lua b/testes/constructs.lua index 6ac68166..3f6d506f 100644 --- a/testes/constructs.lua +++ b/testes/constructs.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/constructs.lua $ | 1 | -- $Id: testes/constructs.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | ;;print "testing syntax";; | 4 | ;;print "testing syntax";; |
5 | 5 | ||
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index abc08039..17f6ceba 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/coroutine.lua $ | 1 | -- $Id: testes/coroutine.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print "testing coroutines" | 4 | print "testing coroutines" |
5 | 5 | ||
@@ -505,6 +505,25 @@ assert(not pcall(a, a)) | |||
505 | a = nil | 505 | a = nil |
506 | 506 | ||
507 | 507 | ||
508 | do | ||
509 | -- bug in 5.4: thread can use message handler higher in the stack | ||
510 | -- than the variable being closed | ||
511 | local c = coroutine.create(function() | ||
512 | local clo <close> = setmetatable({}, {__close=function() | ||
513 | local x = 134 -- will overwrite message handler | ||
514 | error(x) | ||
515 | end}) | ||
516 | -- yields coroutine but leaves a new message handler for it, | ||
517 | -- that would be used when closing the coroutine (except that it | ||
518 | -- will be overwritten) | ||
519 | xpcall(coroutine.yield, function() return "XXX" end) | ||
520 | end) | ||
521 | |||
522 | assert(coroutine.resume(c)) -- start coroutine | ||
523 | local st, msg = coroutine.close(c) | ||
524 | assert(not st and msg == 134) | ||
525 | end | ||
526 | |||
508 | -- access to locals of erroneous coroutines | 527 | -- access to locals of erroneous coroutines |
509 | local x = coroutine.create (function () | 528 | local x = coroutine.create (function () |
510 | local a = 10 | 529 | local a = 10 |
diff --git a/testes/cstack.lua b/testes/cstack.lua index 97afe9fd..0a68a30a 100644 --- a/testes/cstack.lua +++ b/testes/cstack.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/cstack.lua $ | 1 | -- $Id: testes/cstack.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | 4 | ||
5 | local tracegc = require"tracegc" | 5 | local tracegc = require"tracegc" |
diff --git a/testes/db.lua b/testes/db.lua index 75730d27..3c821ab7 100644 --- a/testes/db.lua +++ b/testes/db.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/db.lua $ | 1 | -- $Id: testes/db.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | -- testing debug library | 4 | -- testing debug library |
5 | 5 | ||
diff --git a/testes/errors.lua b/testes/errors.lua index 5fdb7722..c1c40fec 100644 --- a/testes/errors.lua +++ b/testes/errors.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/errors.lua $ | 1 | -- $Id: testes/errors.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print("testing errors") | 4 | print("testing errors") |
5 | 5 | ||
@@ -46,7 +46,7 @@ end | |||
46 | assert(doit("error('hi', 0)") == 'hi') | 46 | assert(doit("error('hi', 0)") == 'hi') |
47 | 47 | ||
48 | -- test nil error message | 48 | -- test nil error message |
49 | assert(doit("error()") == "<error object is nil>") | 49 | assert(doit("error()") == "<no error object>") |
50 | 50 | ||
51 | 51 | ||
52 | -- test common errors/errors that crashed in the past | 52 | -- test common errors/errors that crashed in the past |
@@ -162,6 +162,9 @@ checkmessage("aaa=(1)..{}", "a table value") | |||
162 | -- bug in 5.4.6 | 162 | -- bug in 5.4.6 |
163 | checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'") | 163 | checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'") |
164 | 164 | ||
165 | -- a similar bug, since 5.4.0 | ||
166 | checkmessage("print(('_ENV').x + 1)", "field 'x'") | ||
167 | |||
165 | _G.aaa, _G.bbbb = nil | 168 | _G.aaa, _G.bbbb = nil |
166 | 169 | ||
167 | -- calls | 170 | -- calls |
@@ -614,7 +617,7 @@ do | |||
614 | assert(not res and msg == t) | 617 | assert(not res and msg == t) |
615 | 618 | ||
616 | res, msg = pcall(function () error(nil) end) | 619 | res, msg = pcall(function () error(nil) end) |
617 | assert(not res and msg == "<error object is nil>") | 620 | assert(not res and msg == "<no error object>") |
618 | 621 | ||
619 | local function f() error{msg='x'} end | 622 | local function f() error{msg='x'} end |
620 | res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end) | 623 | res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end) |
diff --git a/testes/events.lua b/testes/events.lua index 5360ac30..7e434b1f 100644 --- a/testes/events.lua +++ b/testes/events.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/events.lua $ | 1 | -- $Id: testes/events.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print('testing metatables') | 4 | print('testing metatables') |
5 | 5 | ||
@@ -379,6 +379,17 @@ x = 0 .."a".."b"..c..d.."e".."f".."g" | |||
379 | assert(x.val == "0abcdefg") | 379 | assert(x.val == "0abcdefg") |
380 | 380 | ||
381 | 381 | ||
382 | do | ||
383 | -- bug since 5.4.1 (test needs T) | ||
384 | local mt = setmetatable({__newindex={}}, {__mode='v'}) | ||
385 | local t = setmetatable({}, mt) | ||
386 | |||
387 | if T then T.allocfailnext() end | ||
388 | |||
389 | -- seg. fault | ||
390 | for i=1, 10 do t[i] = 1 end | ||
391 | end | ||
392 | |||
382 | -- concat metamethod x numbers (bug in 5.1.1) | 393 | -- concat metamethod x numbers (bug in 5.1.1) |
383 | c = {} | 394 | c = {} |
384 | local x | 395 | local x |
@@ -481,7 +492,7 @@ assert(not pcall(function (a,b) return a[b] end, a, 10)) | |||
481 | assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true)) | 492 | assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true)) |
482 | 493 | ||
483 | -- bug in 5.1 | 494 | -- bug in 5.1 |
484 | T, K, V = nil | 495 | local T, K, V = nil |
485 | grandparent = {} | 496 | grandparent = {} |
486 | grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end | 497 | grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end |
487 | 498 | ||
diff --git a/testes/files.lua b/testes/files.lua index 9bdf04d0..05fae49b 100644 --- a/testes/files.lua +++ b/testes/files.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/files.lua $ | 1 | -- $Id: testes/files.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | local debug = require "debug" | 4 | local debug = require "debug" |
5 | 5 | ||
diff --git a/testes/gc.lua b/testes/gc.lua index 09bfe09a..0693837c 100644 --- a/testes/gc.lua +++ b/testes/gc.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/gc.lua $ | 1 | -- $Id: testes/gc.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print('testing incremental garbage collection') | 4 | print('testing incremental garbage collection') |
5 | 5 | ||
@@ -601,6 +601,21 @@ end | |||
601 | 601 | ||
602 | 602 | ||
603 | if T then | 603 | if T then |
604 | collectgarbage("stop") | ||
605 | T.gcstate("pause") | ||
606 | local sup = {x = 0} | ||
607 | local a = setmetatable({}, {__newindex = sup}) | ||
608 | T.gcstate("enteratomic") | ||
609 | assert(T.gccolor(sup) == "black") | ||
610 | a.x = {} -- should not break the invariant | ||
611 | assert(not (T.gccolor(sup) == "black" and T.gccolor(sup.x) == "white")) | ||
612 | T.gcstate("pause") -- complete the GC cycle | ||
613 | sup.x.y = 10 | ||
614 | collectgarbage("restart") | ||
615 | end | ||
616 | |||
617 | |||
618 | if T then | ||
604 | print("emergency collections") | 619 | print("emergency collections") |
605 | collectgarbage() | 620 | collectgarbage() |
606 | collectgarbage() | 621 | collectgarbage() |
diff --git a/testes/gengc.lua b/testes/gengc.lua index c4f6ca1b..ea99bdc4 100644 --- a/testes/gengc.lua +++ b/testes/gengc.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/gengc.lua $ | 1 | -- $Id: testes/gengc.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print('testing generational garbage collection') | 4 | print('testing generational garbage collection') |
5 | 5 | ||
diff --git a/testes/goto.lua b/testes/goto.lua index 103cccef..eca68516 100644 --- a/testes/goto.lua +++ b/testes/goto.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/goto.lua $ | 1 | -- $Id: testes/goto.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | collectgarbage() | 4 | collectgarbage() |
5 | 5 | ||
diff --git a/testes/heavy.lua b/testes/heavy.lua index 4731c747..3b4e4ce3 100644 --- a/testes/heavy.lua +++ b/testes/heavy.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: heavy.lua,v 1.7 2017/12/29 15:42:15 roberto Exp $ | 1 | -- $Id: testes/heavy.lua,v $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | local function teststring () | 4 | local function teststring () |
5 | print("creating a string too long") | 5 | print("creating a string too long") |
diff --git a/testes/literals.lua b/testes/literals.lua index 30ab9ab1..28995718 100644 --- a/testes/literals.lua +++ b/testes/literals.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/literals.lua $ | 1 | -- $Id: testes/literals.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print('testing scanner') | 4 | print('testing scanner') |
5 | 5 | ||
diff --git a/testes/locals.lua b/testes/locals.lua index 910deb8a..ccea0a14 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/locals.lua $ | 1 | -- $Id: testes/locals.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print('testing local variables and environments') | 4 | print('testing local variables and environments') |
5 | 5 | ||
diff --git a/testes/main.lua b/testes/main.lua index e0e9cbe8..bf3c898e 100644 --- a/testes/main.lua +++ b/testes/main.lua | |||
@@ -1,6 +1,6 @@ | |||
1 | # testing special comment on first line | 1 | # testing special comment on first line |
2 | -- $Id: testes/main.lua $ | 2 | -- $Id: testes/main.lua $ |
3 | -- See Copyright Notice in file all.lua | 3 | -- See Copyright Notice in file lua.h |
4 | 4 | ||
5 | -- most (all?) tests here assume a reasonable "Unix-like" shell | 5 | -- most (all?) tests here assume a reasonable "Unix-like" shell |
6 | if _port then return end | 6 | if _port then return end |
diff --git a/testes/math.lua b/testes/math.lua index 3937b9ce..bad8bc5e 100644 --- a/testes/math.lua +++ b/testes/math.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/math.lua $ | 1 | -- $Id: testes/math.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print("testing numbers and math lib") | 4 | print("testing numbers and math lib") |
5 | 5 | ||
diff --git a/testes/memerr.lua b/testes/memerr.lua new file mode 100644 index 00000000..77cb47cb --- /dev/null +++ b/testes/memerr.lua | |||
@@ -0,0 +1,266 @@ | |||
1 | -- $Id: testes/memerr.lua $ | ||
2 | -- See Copyright Notice in file lua.h | ||
3 | |||
4 | |||
5 | local function checkerr (msg, f, ...) | ||
6 | local stat, err = pcall(f, ...) | ||
7 | assert(not stat and string.find(err, msg)) | ||
8 | end | ||
9 | |||
10 | if T==nil then | ||
11 | (Message or print) | ||
12 | ('\n >>> testC not active: skipping memory error tests <<<\n') | ||
13 | return | ||
14 | end | ||
15 | |||
16 | print("testing memory-allocation errors") | ||
17 | |||
18 | local debug = require "debug" | ||
19 | |||
20 | local pack = table.pack | ||
21 | |||
22 | -- standard error message for memory errors | ||
23 | local MEMERRMSG = "not enough memory" | ||
24 | |||
25 | |||
26 | -- memory error in panic function | ||
27 | T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k) | ||
28 | assert(T.checkpanic("newuserdata 20000") == MEMERRMSG) | ||
29 | T.totalmem(0) -- restore high limit | ||
30 | |||
31 | |||
32 | |||
33 | -- {================================================================== | ||
34 | -- Testing memory limits | ||
35 | -- =================================================================== | ||
36 | |||
37 | checkerr("block too big", T.newuserdata, math.maxinteger) | ||
38 | collectgarbage() | ||
39 | local f = load"local a={}; for i=1,100000 do a[i]=i end" | ||
40 | T.alloccount(10) | ||
41 | checkerr(MEMERRMSG, f) | ||
42 | T.alloccount() -- remove limit | ||
43 | |||
44 | |||
45 | -- test memory errors; increase limit for maximum memory by steps, | ||
46 | -- o that we get memory errors in all allocations of a given | ||
47 | -- task, until there is enough memory to complete the task without | ||
48 | -- errors. | ||
49 | local function testbytes (s, f) | ||
50 | collectgarbage() | ||
51 | local M = T.totalmem() | ||
52 | local oldM = M | ||
53 | local a,b = nil | ||
54 | while true do | ||
55 | collectgarbage(); collectgarbage() | ||
56 | T.totalmem(M) | ||
57 | a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f) | ||
58 | T.totalmem(0) -- remove limit | ||
59 | if a and b == "OK" then break end -- stop when no more errors | ||
60 | if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error? | ||
61 | error(a, 0) -- propagate it | ||
62 | end | ||
63 | M = M + 7 -- increase memory limit | ||
64 | end | ||
65 | print(string.format("minimum memory for %s: %d bytes", s, M - oldM)) | ||
66 | return a | ||
67 | end | ||
68 | |||
69 | -- test memory errors; increase limit for number of allocations one | ||
70 | -- by one, so that we get memory errors in all allocations of a given | ||
71 | -- task, until there is enough allocations to complete the task without | ||
72 | -- errors. | ||
73 | |||
74 | local function testalloc (s, f) | ||
75 | collectgarbage() | ||
76 | local M = 0 | ||
77 | local a,b = nil | ||
78 | while true do | ||
79 | collectgarbage(); collectgarbage() | ||
80 | T.alloccount(M) | ||
81 | a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f) | ||
82 | T.alloccount() -- remove limit | ||
83 | if a and b == "OK" then break end -- stop when no more errors | ||
84 | if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error? | ||
85 | error(a, 0) -- propagate it | ||
86 | end | ||
87 | M = M + 1 -- increase allocation limit | ||
88 | end | ||
89 | print(string.format("minimum allocations for %s: %d allocations", s, M)) | ||
90 | return a | ||
91 | end | ||
92 | |||
93 | |||
94 | local function testamem (s, f) | ||
95 | testalloc(s, f) | ||
96 | return testbytes(s, f) | ||
97 | end | ||
98 | |||
99 | |||
100 | -- doing nothing | ||
101 | b = testamem("doing nothing", function () return 10 end) | ||
102 | assert(b == 10) | ||
103 | |||
104 | -- testing memory errors when creating a new state | ||
105 | |||
106 | testamem("state creation", function () | ||
107 | local st = T.newstate() | ||
108 | if st then T.closestate(st) end -- close new state | ||
109 | return st | ||
110 | end) | ||
111 | |||
112 | testamem("empty-table creation", function () | ||
113 | return {} | ||
114 | end) | ||
115 | |||
116 | testamem("string creation", function () | ||
117 | return "XXX" .. "YYY" | ||
118 | end) | ||
119 | |||
120 | testamem("coroutine creation", function() | ||
121 | return coroutine.create(print) | ||
122 | end) | ||
123 | |||
124 | |||
125 | -- testing to-be-closed variables | ||
126 | testamem("to-be-closed variables", function() | ||
127 | local flag | ||
128 | do | ||
129 | local x <close> = | ||
130 | setmetatable({}, {__close = function () flag = true end}) | ||
131 | flag = false | ||
132 | local x = {} | ||
133 | end | ||
134 | return flag | ||
135 | end) | ||
136 | |||
137 | |||
138 | -- testing threads | ||
139 | |||
140 | -- get main thread from registry | ||
141 | local mt = T.testC("rawgeti R !M; return 1") | ||
142 | assert(type(mt) == "thread" and coroutine.running() == mt) | ||
143 | |||
144 | |||
145 | |||
146 | local function expand (n,s) | ||
147 | if n==0 then return "" end | ||
148 | local e = string.rep("=", n) | ||
149 | return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n", | ||
150 | e, s, expand(n-1,s), e) | ||
151 | end | ||
152 | |||
153 | G=0; collectgarbage(); a =collectgarbage("count") | ||
154 | load(expand(20,"G=G+1"))() | ||
155 | assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1) | ||
156 | G = nil | ||
157 | |||
158 | testamem("running code on new thread", function () | ||
159 | return T.doonnewstack("local x=1") == 0 -- try to create thread | ||
160 | end) | ||
161 | |||
162 | |||
163 | -- testing memory x compiler | ||
164 | |||
165 | testamem("loadstring", function () | ||
166 | return load("x=1") -- try to do load a string | ||
167 | end) | ||
168 | |||
169 | |||
170 | local testprog = [[ | ||
171 | local function foo () return end | ||
172 | local t = {"x"} | ||
173 | AA = "aaa" | ||
174 | for i = 1, #t do AA = AA .. t[i] end | ||
175 | return true | ||
176 | ]] | ||
177 | |||
178 | -- testing memory x dofile | ||
179 | _G.AA = nil | ||
180 | local t =os.tmpname() | ||
181 | local f = assert(io.open(t, "w")) | ||
182 | f:write(testprog) | ||
183 | f:close() | ||
184 | testamem("dofile", function () | ||
185 | local a = loadfile(t) | ||
186 | return a and a() | ||
187 | end) | ||
188 | assert(os.remove(t)) | ||
189 | assert(_G.AA == "aaax") | ||
190 | |||
191 | |||
192 | -- other generic tests | ||
193 | |||
194 | testamem("gsub", function () | ||
195 | local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end) | ||
196 | return (a == 'ablo ablo') | ||
197 | end) | ||
198 | |||
199 | testamem("dump/undump", function () | ||
200 | local a = load(testprog) | ||
201 | local b = a and string.dump(a) | ||
202 | a = b and load(b) | ||
203 | return a and a() | ||
204 | end) | ||
205 | |||
206 | _G.AA = nil | ||
207 | |||
208 | local t = os.tmpname() | ||
209 | testamem("file creation", function () | ||
210 | local f = assert(io.open(t, 'w')) | ||
211 | assert (not io.open"nomenaoexistente") | ||
212 | io.close(f); | ||
213 | return not loadfile'nomenaoexistente' | ||
214 | end) | ||
215 | assert(os.remove(t)) | ||
216 | |||
217 | testamem("table creation", function () | ||
218 | local a, lim = {}, 10 | ||
219 | for i=1,lim do a[i] = i; a[i..'a'] = {} end | ||
220 | return (type(a[lim..'a']) == 'table' and a[lim] == lim) | ||
221 | end) | ||
222 | |||
223 | testamem("constructors", function () | ||
224 | local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5} | ||
225 | return (type(a) == 'table' and a.e == 5) | ||
226 | end) | ||
227 | |||
228 | local a = 1 | ||
229 | local close = nil | ||
230 | testamem("closure creation", function () | ||
231 | function close (b) | ||
232 | return function (x) return b + x end | ||
233 | end | ||
234 | return (close(2)(4) == 6) | ||
235 | end) | ||
236 | |||
237 | testamem("using coroutines", function () | ||
238 | local a = coroutine.wrap(function () | ||
239 | coroutine.yield(string.rep("a", 10)) | ||
240 | return {} | ||
241 | end) | ||
242 | assert(string.len(a()) == 10) | ||
243 | return a() | ||
244 | end) | ||
245 | |||
246 | do -- auxiliary buffer | ||
247 | local lim = 100 | ||
248 | local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end | ||
249 | testamem("auxiliary buffer", function () | ||
250 | return (#table.concat(a, ",") == 20*lim + lim - 1) | ||
251 | end) | ||
252 | end | ||
253 | |||
254 | testamem("growing stack", function () | ||
255 | local function foo (n) | ||
256 | if n == 0 then return 1 else return 1 + foo(n - 1) end | ||
257 | end | ||
258 | return foo(100) | ||
259 | end) | ||
260 | |||
261 | -- }================================================================== | ||
262 | |||
263 | |||
264 | print "Ok" | ||
265 | |||
266 | |||
diff --git a/testes/nextvar.lua b/testes/nextvar.lua index d1da3cee..031ad3fd 100644 --- a/testes/nextvar.lua +++ b/testes/nextvar.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/nextvar.lua $ | 1 | -- $Id: testes/nextvar.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print('testing tables, next, and for') | 4 | print('testing tables, next, and for') |
5 | 5 | ||
diff --git a/testes/packtests b/testes/packtests index 0dbb92fe..855c054a 100755 --- a/testes/packtests +++ b/testes/packtests | |||
@@ -28,6 +28,7 @@ $NAME/literals.lua \ | |||
28 | $NAME/locals.lua \ | 28 | $NAME/locals.lua \ |
29 | $NAME/main.lua \ | 29 | $NAME/main.lua \ |
30 | $NAME/math.lua \ | 30 | $NAME/math.lua \ |
31 | $NAME/memerr.lua \ | ||
31 | $NAME/nextvar.lua \ | 32 | $NAME/nextvar.lua \ |
32 | $NAME/pm.lua \ | 33 | $NAME/pm.lua \ |
33 | $NAME/sort.lua \ | 34 | $NAME/sort.lua \ |
diff --git a/testes/pm.lua b/testes/pm.lua index f5889fcd..2a0cfb0b 100644 --- a/testes/pm.lua +++ b/testes/pm.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/pm.lua $ | 1 | -- $Id: testes/pm.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | -- UTF-8 file | 4 | -- UTF-8 file |
5 | 5 | ||
diff --git a/testes/sort.lua b/testes/sort.lua index 290b199e..b0127660 100644 --- a/testes/sort.lua +++ b/testes/sort.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/sort.lua $ | 1 | -- $Id: testes/sort.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print "testing (parts of) table library" | 4 | print "testing (parts of) table library" |
5 | 5 | ||
diff --git a/testes/strings.lua b/testes/strings.lua index 9bb52b35..ce28e4c5 100644 --- a/testes/strings.lua +++ b/testes/strings.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/strings.lua $ | 1 | -- $Id: testes/strings.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | -- ISO Latin encoding | 4 | -- ISO Latin encoding |
5 | 5 | ||
diff --git a/testes/tpack.lua b/testes/tpack.lua index 4b32efb5..70386178 100644 --- a/testes/tpack.lua +++ b/testes/tpack.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/tpack.lua $ | 1 | -- $Id: testes/tpack.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | local pack = string.pack | 4 | local pack = string.pack |
5 | local packsize = string.packsize | 5 | local packsize = string.packsize |
diff --git a/testes/utf8.lua b/testes/utf8.lua index dc0f2f09..0704782c 100644 --- a/testes/utf8.lua +++ b/testes/utf8.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/utf8.lua $ | 1 | -- $Id: testes/utf8.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | -- UTF-8 file | 4 | -- UTF-8 file |
5 | 5 | ||
diff --git a/testes/vararg.lua b/testes/vararg.lua index 1b025102..10553de2 100644 --- a/testes/vararg.lua +++ b/testes/vararg.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/vararg.lua $ | 1 | -- $Id: testes/vararg.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print('testing vararg') | 4 | print('testing vararg') |
5 | 5 | ||
diff --git a/testes/verybig.lua b/testes/verybig.lua index 250ea795..8163802c 100644 --- a/testes/verybig.lua +++ b/testes/verybig.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/verybig.lua $ | 1 | -- $Id: testes/verybig.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print "testing RK" | 4 | print "testing RK" |
5 | 5 | ||