diff options
Diffstat (limited to '')
-rw-r--r-- | lbaselib.c | 15 | ||||
-rw-r--r-- | ldo.c | 13 | ||||
-rw-r--r-- | lfunc.c | 6 | ||||
-rw-r--r-- | lobject.h | 1 | ||||
-rw-r--r-- | lstring.c | 2 | ||||
-rw-r--r-- | ltests.c | 7 | ||||
-rw-r--r-- | lundump.c | 42 | ||||
-rw-r--r-- | lundump.h | 3 | ||||
-rw-r--r-- | lzio.c | 36 | ||||
-rw-r--r-- | lzio.h | 1 | ||||
-rw-r--r-- | manual/manual.of | 17 | ||||
-rw-r--r-- | testes/api.lua | 51 |
12 files changed, 160 insertions, 34 deletions
@@ -337,9 +337,20 @@ static int load_aux (lua_State *L, int status, int envidx) { | |||
337 | } | 337 | } |
338 | 338 | ||
339 | 339 | ||
340 | static const char *getmode (lua_State *L, int idx) { | ||
341 | const char *mode = luaL_optstring(L, idx, "bt"); | ||
342 | int i = 0; | ||
343 | if (mode[i] == 'b') i++; | ||
344 | if (mode[i] == 't') i++; | ||
345 | if (mode[i] != '\0') | ||
346 | luaL_argerror(L, idx, "invalid mode"); | ||
347 | return mode; | ||
348 | } | ||
349 | |||
350 | |||
340 | static int luaB_loadfile (lua_State *L) { | 351 | static int luaB_loadfile (lua_State *L) { |
341 | const char *fname = luaL_optstring(L, 1, NULL); | 352 | const char *fname = luaL_optstring(L, 1, NULL); |
342 | const char *mode = luaL_optstring(L, 2, NULL); | 353 | const char *mode = getmode(L, 2); |
343 | int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ | 354 | int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ |
344 | int status = luaL_loadfilex(L, fname, mode); | 355 | int status = luaL_loadfilex(L, fname, mode); |
345 | return load_aux(L, status, env); | 356 | return load_aux(L, status, env); |
@@ -388,7 +399,7 @@ static int luaB_load (lua_State *L) { | |||
388 | int status; | 399 | int status; |
389 | size_t l; | 400 | size_t l; |
390 | const char *s = lua_tolstring(L, 1, &l); | 401 | const char *s = lua_tolstring(L, 1, &l); |
391 | const char *mode = luaL_optstring(L, 3, "bt"); | 402 | const char *mode = getmode(L, 3); |
392 | int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ | 403 | int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ |
393 | if (s != NULL) { /* loading a string? */ | 404 | if (s != NULL) { /* loading a string? */ |
394 | const char *chunkname = luaL_optstring(L, 2, s); | 405 | const char *chunkname = luaL_optstring(L, 2, s); |
@@ -977,7 +977,7 @@ struct SParser { /* data to 'f_parser' */ | |||
977 | 977 | ||
978 | 978 | ||
979 | static void checkmode (lua_State *L, const char *mode, const char *x) { | 979 | static void checkmode (lua_State *L, const char *mode, const char *x) { |
980 | if (mode && strchr(mode, x[0]) == NULL) { | 980 | if (strchr(mode, x[0]) == NULL) { |
981 | luaO_pushfstring(L, | 981 | luaO_pushfstring(L, |
982 | "attempt to load a %s chunk (mode is '%s')", x, mode); | 982 | "attempt to load a %s chunk (mode is '%s')", x, mode); |
983 | luaD_throw(L, LUA_ERRSYNTAX); | 983 | luaD_throw(L, LUA_ERRSYNTAX); |
@@ -988,13 +988,18 @@ static void checkmode (lua_State *L, const char *mode, const char *x) { | |||
988 | static void f_parser (lua_State *L, void *ud) { | 988 | static void f_parser (lua_State *L, void *ud) { |
989 | LClosure *cl; | 989 | LClosure *cl; |
990 | struct SParser *p = cast(struct SParser *, ud); | 990 | struct SParser *p = cast(struct SParser *, ud); |
991 | const char *mode = p->mode ? p->mode : "bt"; | ||
991 | int c = zgetc(p->z); /* read first character */ | 992 | int c = zgetc(p->z); /* read first character */ |
992 | if (c == LUA_SIGNATURE[0]) { | 993 | if (c == LUA_SIGNATURE[0]) { |
993 | checkmode(L, p->mode, "binary"); | 994 | int fixed = 0; |
994 | cl = luaU_undump(L, p->z, p->name); | 995 | if (strchr(mode, 'B') != NULL) |
996 | fixed = 1; | ||
997 | else | ||
998 | checkmode(L, mode, "binary"); | ||
999 | cl = luaU_undump(L, p->z, p->name, fixed); | ||
995 | } | 1000 | } |
996 | else { | 1001 | else { |
997 | checkmode(L, p->mode, "text"); | 1002 | checkmode(L, mode, "text"); |
998 | cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); | 1003 | cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); |
999 | } | 1004 | } |
1000 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); | 1005 | lua_assert(cl->nupvalues == cl->p->sizeupvalues); |
@@ -265,10 +265,12 @@ Proto *luaF_newproto (lua_State *L) { | |||
265 | 265 | ||
266 | 266 | ||
267 | void luaF_freeproto (lua_State *L, Proto *f) { | 267 | void luaF_freeproto (lua_State *L, Proto *f) { |
268 | luaM_freearray(L, f->code, f->sizecode); | 268 | if (!(f->flag & PF_FIXED)) { |
269 | luaM_freearray(L, f->code, f->sizecode); | ||
270 | luaM_freearray(L, f->lineinfo, f->sizelineinfo); | ||
271 | } | ||
269 | luaM_freearray(L, f->p, f->sizep); | 272 | luaM_freearray(L, f->p, f->sizep); |
270 | luaM_freearray(L, f->k, f->sizek); | 273 | luaM_freearray(L, f->k, f->sizek); |
271 | luaM_freearray(L, f->lineinfo, f->sizelineinfo); | ||
272 | luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo); | 274 | luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo); |
273 | luaM_freearray(L, f->locvars, f->sizelocvars); | 275 | luaM_freearray(L, f->locvars, f->sizelocvars); |
274 | luaM_freearray(L, f->upvalues, f->sizeupvalues); | 276 | luaM_freearray(L, f->upvalues, f->sizeupvalues); |
@@ -556,6 +556,7 @@ typedef struct AbsLineInfo { | |||
556 | ** Flags in Prototypes | 556 | ** Flags in Prototypes |
557 | */ | 557 | */ |
558 | #define PF_ISVARARG 1 | 558 | #define PF_ISVARARG 1 |
559 | #define PF_FIXED 2 /* prototype has parts in fixed memory */ | ||
559 | 560 | ||
560 | 561 | ||
561 | /* | 562 | /* |
@@ -207,8 +207,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { | |||
207 | list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ | 207 | list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ |
208 | } | 208 | } |
209 | ts = createstrobj(L, l, LUA_VSHRSTR, h); | 209 | ts = createstrobj(L, l, LUA_VSHRSTR, h); |
210 | memcpy(getshrstr(ts), str, l * sizeof(char)); | ||
211 | ts->shrlen = cast_byte(l); | 210 | ts->shrlen = cast_byte(l); |
211 | memcpy(getshrstr(ts), str, l * sizeof(char)); | ||
212 | ts->u.hnext = *list; | 212 | ts->u.hnext = *list; |
213 | *list = ts; | 213 | *list = ts; |
214 | tb->nuse++; | 214 | tb->nuse++; |
@@ -1513,8 +1513,11 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { | |||
1513 | luaL_loadfile(L1, luaL_checkstring(L1, getnum)); | 1513 | luaL_loadfile(L1, luaL_checkstring(L1, getnum)); |
1514 | } | 1514 | } |
1515 | else if EQ("loadstring") { | 1515 | else if EQ("loadstring") { |
1516 | const char *s = luaL_checkstring(L1, getnum); | 1516 | size_t slen; |
1517 | luaL_loadstring(L1, s); | 1517 | const char *s = luaL_checklstring(L1, getnum, &slen); |
1518 | const char *name = getstring; | ||
1519 | const char *mode = getstring; | ||
1520 | luaL_loadbufferx(L1, s, slen, name, mode); | ||
1518 | } | 1521 | } |
1519 | else if EQ("newmetatable") { | 1522 | else if EQ("newmetatable") { |
1520 | lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); | 1523 | lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); |
@@ -38,6 +38,7 @@ typedef struct { | |||
38 | Table *h; /* list for string reuse */ | 38 | Table *h; /* list for string reuse */ |
39 | lu_mem offset; /* current position relative to beginning of dump */ | 39 | lu_mem offset; /* current position relative to beginning of dump */ |
40 | lua_Integer nstr; /* number of strings in the list */ | 40 | lua_Integer nstr; /* number of strings in the list */ |
41 | lu_byte fixed; /* dump is fixed in memory */ | ||
41 | } LoadState; | 42 | } LoadState; |
42 | 43 | ||
43 | 44 | ||
@@ -70,6 +71,16 @@ static void loadAlign (LoadState *S, int align) { | |||
70 | } | 71 | } |
71 | 72 | ||
72 | 73 | ||
74 | #define getaddr(S,n,t) cast(t *, getaddr_(S,n,sizeof(t))) | ||
75 | |||
76 | static const void *getaddr_ (LoadState *S, int n, int sz) { | ||
77 | const void *block = luaZ_getaddr(S->Z, n * sz); | ||
78 | if (block == NULL) | ||
79 | error(S, "truncated fixed buffer"); | ||
80 | return block; | ||
81 | } | ||
82 | |||
83 | |||
73 | #define loadVar(S,x) loadVector(S,&x,1) | 84 | #define loadVar(S,x) loadVector(S,&x,1) |
74 | 85 | ||
75 | 86 | ||
@@ -169,10 +180,16 @@ static TString *loadString (LoadState *S, Proto *p) { | |||
169 | 180 | ||
170 | static void loadCode (LoadState *S, Proto *f) { | 181 | static void loadCode (LoadState *S, Proto *f) { |
171 | int n = loadInt(S); | 182 | int n = loadInt(S); |
172 | f->code = luaM_newvectorchecked(S->L, n, Instruction); | ||
173 | f->sizecode = n; | ||
174 | loadAlign(S, sizeof(f->code[0])); | 183 | loadAlign(S, sizeof(f->code[0])); |
175 | loadVector(S, f->code, n); | 184 | if (S->fixed) { |
185 | f->code = getaddr(S, n, Instruction); | ||
186 | f->sizecode = n; | ||
187 | } | ||
188 | else { | ||
189 | f->code = luaM_newvectorchecked(S->L, n, Instruction); | ||
190 | f->sizecode = n; | ||
191 | loadVector(S, f->code, n); | ||
192 | } | ||
176 | } | 193 | } |
177 | 194 | ||
178 | 195 | ||
@@ -254,9 +271,15 @@ static void loadUpvalues (LoadState *S, Proto *f) { | |||
254 | static void loadDebug (LoadState *S, Proto *f) { | 271 | static void loadDebug (LoadState *S, Proto *f) { |
255 | int i, n; | 272 | int i, n; |
256 | n = loadInt(S); | 273 | n = loadInt(S); |
257 | f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); | 274 | if (S->fixed) { |
258 | f->sizelineinfo = n; | 275 | f->lineinfo = getaddr(S, n, ls_byte); |
259 | loadVector(S, f->lineinfo, n); | 276 | f->sizelineinfo = n; |
277 | } | ||
278 | else { | ||
279 | f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); | ||
280 | f->sizelineinfo = n; | ||
281 | loadVector(S, f->lineinfo, n); | ||
282 | } | ||
260 | n = loadInt(S); | 283 | n = loadInt(S); |
261 | f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); | 284 | f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); |
262 | f->sizeabslineinfo = n; | 285 | f->sizeabslineinfo = n; |
@@ -287,7 +310,9 @@ static void loadFunction (LoadState *S, Proto *f) { | |||
287 | f->linedefined = loadInt(S); | 310 | f->linedefined = loadInt(S); |
288 | f->lastlinedefined = loadInt(S); | 311 | f->lastlinedefined = loadInt(S); |
289 | f->numparams = loadByte(S); | 312 | f->numparams = loadByte(S); |
290 | f->flag = loadByte(S) & PF_ISVARARG; /* keep only the meaningful flags */ | 313 | f->flag = loadByte(S) & PF_ISVARARG; /* get only the meaningful flags */ |
314 | if (S->fixed) | ||
315 | f->flag |= PF_FIXED; /* signal that code is fixed */ | ||
291 | f->maxstacksize = loadByte(S); | 316 | f->maxstacksize = loadByte(S); |
292 | loadCode(S, f); | 317 | loadCode(S, f); |
293 | loadConstants(S, f); | 318 | loadConstants(S, f); |
@@ -335,7 +360,7 @@ static void checkHeader (LoadState *S) { | |||
335 | /* | 360 | /* |
336 | ** Load precompiled chunk. | 361 | ** Load precompiled chunk. |
337 | */ | 362 | */ |
338 | LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name) { | 363 | LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) { |
339 | LoadState S; | 364 | LoadState S; |
340 | LClosure *cl; | 365 | LClosure *cl; |
341 | if (*name == '@' || *name == '=') | 366 | if (*name == '@' || *name == '=') |
@@ -346,6 +371,7 @@ LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name) { | |||
346 | S.name = name; | 371 | S.name = name; |
347 | S.L = L; | 372 | S.L = L; |
348 | S.Z = Z; | 373 | S.Z = Z; |
374 | S.fixed = fixed; | ||
349 | S.offset = 1; /* fist byte was already read */ | 375 | S.offset = 1; /* fist byte was already read */ |
350 | checkHeader(&S); | 376 | checkHeader(&S); |
351 | cl = luaF_newLclosure(L, loadByte(&S)); | 377 | cl = luaF_newLclosure(L, loadByte(&S)); |
@@ -26,7 +26,8 @@ | |||
26 | #define LUAC_FORMAT 0 /* this is the official format */ | 26 | #define LUAC_FORMAT 0 /* this is the official format */ |
27 | 27 | ||
28 | /* load one chunk; from lundump.c */ | 28 | /* load one chunk; from lundump.c */ |
29 | LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); | 29 | LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name, |
30 | int fixed); | ||
30 | 31 | ||
31 | /* dump one chunk; from ldump.c */ | 32 | /* dump one chunk; from ldump.c */ |
32 | LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, | 33 | LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, |
@@ -45,17 +45,25 @@ void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { | |||
45 | 45 | ||
46 | 46 | ||
47 | /* --------------------------------------------------------------- read --- */ | 47 | /* --------------------------------------------------------------- read --- */ |
48 | |||
49 | static int checkbuffer (ZIO *z) { | ||
50 | if (z->n == 0) { /* no bytes in buffer? */ | ||
51 | if (luaZ_fill(z) == EOZ) /* try to read more */ | ||
52 | return 0; /* no more input */ | ||
53 | else { | ||
54 | z->n++; /* luaZ_fill consumed first byte; put it back */ | ||
55 | z->p--; | ||
56 | } | ||
57 | } | ||
58 | return 1; /* now buffer has something */ | ||
59 | } | ||
60 | |||
61 | |||
48 | size_t luaZ_read (ZIO *z, void *b, size_t n) { | 62 | size_t luaZ_read (ZIO *z, void *b, size_t n) { |
49 | while (n) { | 63 | while (n) { |
50 | size_t m; | 64 | size_t m; |
51 | if (z->n == 0) { /* no bytes in buffer? */ | 65 | if (!checkbuffer(z)) |
52 | if (luaZ_fill(z) == EOZ) /* try to read more */ | 66 | return n; /* no more input; return number of missing bytes */ |
53 | return n; /* no more input; return number of missing bytes */ | ||
54 | else { | ||
55 | z->n++; /* luaZ_fill consumed first byte; put it back */ | ||
56 | z->p--; | ||
57 | } | ||
58 | } | ||
59 | m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ | 67 | m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ |
60 | memcpy(b, z->p, m); | 68 | memcpy(b, z->p, m); |
61 | z->n -= m; | 69 | z->n -= m; |
@@ -66,3 +74,15 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) { | |||
66 | return 0; | 74 | return 0; |
67 | } | 75 | } |
68 | 76 | ||
77 | |||
78 | const void *luaZ_getaddr (ZIO* z, size_t n) { | ||
79 | const void *res; | ||
80 | if (!checkbuffer(z)) | ||
81 | return NULL; /* no more input */ | ||
82 | if (z->n < n) /* not enough bytes? */ | ||
83 | return NULL; /* block not whole; cannot give an address */ | ||
84 | res = z->p; /* get block address */ | ||
85 | z->n -= n; /* consume these bytes */ | ||
86 | z->p += n; | ||
87 | return res; | ||
88 | } | ||
@@ -48,6 +48,7 @@ LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, | |||
48 | void *data); | 48 | void *data); |
49 | LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ | 49 | LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ |
50 | 50 | ||
51 | LUAI_FUNC const void *luaZ_getaddr (ZIO* z, size_t n); | ||
51 | 52 | ||
52 | 53 | ||
53 | /* --------- Private Part ------------------ */ | 54 | /* --------- Private Part ------------------ */ |
diff --git a/manual/manual.of b/manual/manual.of index c16039b4..3eab69fa 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -2730,7 +2730,8 @@ For such errors, Lua does not call the @x{message handler}. | |||
2730 | 2730 | ||
2731 | @item{@defid{LUA_ERRERR}| error while running the @x{message handler}.} | 2731 | @item{@defid{LUA_ERRERR}| error while running the @x{message handler}.} |
2732 | 2732 | ||
2733 | @item{@defid{LUA_ERRSYNTAX}| syntax error during precompilation.} | 2733 | @item{@defid{LUA_ERRSYNTAX}| syntax error during precompilation |
2734 | or format error in a binary chunk.} | ||
2734 | 2735 | ||
2735 | @item{@defid{LUA_YIELD}| the thread (coroutine) yields.} | 2736 | @item{@defid{LUA_YIELD}| the thread (coroutine) yields.} |
2736 | 2737 | ||
@@ -3646,6 +3647,18 @@ and loads it accordingly (see program @idx{luac}). | |||
3646 | The string @id{mode} works as in function @Lid{load}, | 3647 | The string @id{mode} works as in function @Lid{load}, |
3647 | with the addition that | 3648 | with the addition that |
3648 | a @id{NULL} value is equivalent to the string @St{bt}. | 3649 | a @id{NULL} value is equivalent to the string @St{bt}. |
3650 | Moreover, it may have a @Char{B} instead of a @Char{b}, | ||
3651 | meaning a @emphx{fixed buffer} with the binary dump. | ||
3652 | |||
3653 | A fixed buffer means that the address returned by the reader function | ||
3654 | should contain the chunk until everything created by the chunk has | ||
3655 | been collected. | ||
3656 | (In general, a fixed buffer would keep the chunk | ||
3657 | as its contents until the end of the program, | ||
3658 | for instance with the chunk in ROM.) | ||
3659 | Moreover, for a fixed buffer, | ||
3660 | the reader function should return the entire chunk in the first read. | ||
3661 | (As an example, @Lid{luaL_loadbufferx} does that.) | ||
3649 | 3662 | ||
3650 | @id{lua_load} uses the stack internally, | 3663 | @id{lua_load} uses the stack internally, |
3651 | so the reader function must always leave the stack | 3664 | so the reader function must always leave the stack |
@@ -5688,6 +5701,8 @@ This function returns the same results as @Lid{lua_load}. | |||
5688 | @id{name} is the chunk name, | 5701 | @id{name} is the chunk name, |
5689 | used for debug information and error messages. | 5702 | used for debug information and error messages. |
5690 | The string @id{mode} works as in the function @Lid{lua_load}. | 5703 | The string @id{mode} works as in the function @Lid{lua_load}. |
5704 | In particular, this function supports mode @Char{B} for | ||
5705 | fixed buffers. | ||
5691 | 5706 | ||
5692 | } | 5707 | } |
5693 | 5708 | ||
diff --git a/testes/api.lua b/testes/api.lua index dece98f5..181c1d53 100644 --- a/testes/api.lua +++ b/testes/api.lua | |||
@@ -407,7 +407,7 @@ do | |||
407 | concat 3]]) == "hi alo mundo") | 407 | concat 3]]) == "hi alo mundo") |
408 | 408 | ||
409 | -- "argerror" without frames | 409 | -- "argerror" without frames |
410 | assert(T.checkpanic("loadstring 4") == | 410 | assert(T.checkpanic("loadstring 4 name bt") == |
411 | "bad argument #4 (string expected, got no value)") | 411 | "bad argument #4 (string expected, got no value)") |
412 | 412 | ||
413 | 413 | ||
@@ -420,7 +420,7 @@ do | |||
420 | if not _soft then | 420 | if not _soft then |
421 | local msg = T.checkpanic[[ | 421 | local msg = T.checkpanic[[ |
422 | pushstring "function f() f() end" | 422 | pushstring "function f() f() end" |
423 | loadstring -1; call 0 0 | 423 | loadstring -1 name t; call 0 0 |
424 | getglobal f; call 0 0 | 424 | getglobal f; call 0 0 |
425 | ]] | 425 | ]] |
426 | assert(string.find(msg, "stack overflow")) | 426 | assert(string.find(msg, "stack overflow")) |
@@ -430,7 +430,7 @@ do | |||
430 | assert(T.checkpanic([[ | 430 | assert(T.checkpanic([[ |
431 | pushstring "return {__close = function () Y = 'ho'; end}" | 431 | pushstring "return {__close = function () Y = 'ho'; end}" |
432 | newtable | 432 | newtable |
433 | loadstring -2 | 433 | loadstring -2 name t |
434 | call 0 1 | 434 | call 0 1 |
435 | setmetatable -2 | 435 | setmetatable -2 |
436 | toclose -1 | 436 | toclose -1 |
@@ -458,6 +458,8 @@ if not _soft then | |||
458 | print'+' | 458 | print'+' |
459 | end | 459 | end |
460 | 460 | ||
461 | |||
462 | |||
461 | local lim = _soft and 500 or 12000 | 463 | local lim = _soft and 500 or 12000 |
462 | local prog = {"checkstack " .. (lim * 2 + 100) .. "msg", "newtable"} | 464 | local prog = {"checkstack " .. (lim * 2 + 100) .. "msg", "newtable"} |
463 | for i = 1,lim do | 465 | for i = 1,lim do |
@@ -481,10 +483,20 @@ for i = 1,lim do assert(t[i] == i*10); t[i] = undef end | |||
481 | assert(next(t) == nil) | 483 | assert(next(t) == nil) |
482 | prog, g, t = nil | 484 | prog, g, t = nil |
483 | 485 | ||
486 | do -- shrink stack | ||
487 | local m1, m2 = 0, collectgarbage"count" * 1024 | ||
488 | while m1 ~= m2 do -- repeat until stable | ||
489 | collectgarbage() | ||
490 | m1 = m2 | ||
491 | m2 = collectgarbage"count" * 1024 | ||
492 | end | ||
493 | end | ||
494 | |||
495 | |||
484 | -- testing errors | 496 | -- testing errors |
485 | 497 | ||
486 | a = T.testC([[ | 498 | a = T.testC([[ |
487 | loadstring 2; pcall 0 1 0; | 499 | loadstring 2 name t; pcall 0 1 0; |
488 | pushvalue 3; insert -2; pcall 1 1 0; | 500 | pushvalue 3; insert -2; pcall 1 1 0; |
489 | pcall 0 0 0; | 501 | pcall 0 0 0; |
490 | return 1 | 502 | return 1 |
@@ -498,7 +510,7 @@ local function check3(p, ...) | |||
498 | assert(#arg == 3) | 510 | assert(#arg == 3) |
499 | assert(string.find(arg[3], p)) | 511 | assert(string.find(arg[3], p)) |
500 | end | 512 | end |
501 | check3(":1:", T.testC("loadstring 2; return *", "x=")) | 513 | check3(":1:", T.testC("loadstring 2 name t; return *", "x=")) |
502 | check3("%.", T.testC("loadfile 2; return *", ".")) | 514 | check3("%.", T.testC("loadfile 2; return *", ".")) |
503 | check3("xxxx", T.testC("loadfile 2; return *", "xxxx")) | 515 | check3("xxxx", T.testC("loadfile 2; return *", "xxxx")) |
504 | 516 | ||
@@ -509,6 +521,35 @@ local function checkerrnopro (code, msg) | |||
509 | assert(not stt and string.find(err, msg)) | 521 | assert(not stt and string.find(err, msg)) |
510 | end | 522 | end |
511 | 523 | ||
524 | |||
525 | do | ||
526 | print("testing load of binaries in fixed buffers") | ||
527 | local source = {} | ||
528 | local N = 1000 | ||
529 | -- create a somewhat "large" source | ||
530 | for i = 1, N do source[i] = "X = X + 1; " end | ||
531 | source = table.concat(source) | ||
532 | -- give chunk an explicit name to avoid using source as name | ||
533 | source = load(source, "name1") | ||
534 | -- dump without debug information | ||
535 | source = string.dump(source, true) | ||
536 | -- each "X=X+1" generates 4 opcodes with 4 bytes each | ||
537 | assert(#source > N * 4 * 4) | ||
538 | collectgarbage(); collectgarbage() | ||
539 | local m1 = collectgarbage"count" * 1024 | ||
540 | -- load dump using fixed buffer | ||
541 | local code = T.testC([[ | ||
542 | loadstring 2 name B; | ||
543 | return 1 | ||
544 | ]], source) | ||
545 | collectgarbage() | ||
546 | local m2 = collectgarbage"count" * 1024 | ||
547 | -- load used fewer than 300 bytes | ||
548 | assert(m2 > m1 and m2 - m1 < 300) | ||
549 | X = 0; code(); assert(X == N); X = nil | ||
550 | end | ||
551 | |||
552 | |||
512 | if not _soft then | 553 | if not _soft then |
513 | collectgarbage("stop") -- avoid __gc with full stack | 554 | collectgarbage("stop") -- avoid __gc with full stack |
514 | checkerrnopro("pushnum 3; call 0 0", "attempt to call") | 555 | checkerrnopro("pushnum 3; call 0 0", "attempt to call") |