18e3e3a7aSWarner Losh /*
20495ed39SKyle Evans ** $Id: lundump.c $
38e3e3a7aSWarner Losh ** load precompiled Lua chunks
48e3e3a7aSWarner Losh ** See Copyright Notice in lua.h
58e3e3a7aSWarner Losh */
68e3e3a7aSWarner Losh
78e3e3a7aSWarner Losh #define lundump_c
88e3e3a7aSWarner Losh #define LUA_CORE
98e3e3a7aSWarner Losh
108e3e3a7aSWarner Losh #include "lprefix.h"
118e3e3a7aSWarner Losh
128e3e3a7aSWarner Losh
130495ed39SKyle Evans #include <limits.h>
148e3e3a7aSWarner Losh #include <string.h>
158e3e3a7aSWarner Losh
168e3e3a7aSWarner Losh #include "lua.h"
178e3e3a7aSWarner Losh
188e3e3a7aSWarner Losh #include "ldebug.h"
198e3e3a7aSWarner Losh #include "ldo.h"
208e3e3a7aSWarner Losh #include "lfunc.h"
218e3e3a7aSWarner Losh #include "lmem.h"
228e3e3a7aSWarner Losh #include "lobject.h"
238e3e3a7aSWarner Losh #include "lstring.h"
248e3e3a7aSWarner Losh #include "lundump.h"
258e3e3a7aSWarner Losh #include "lzio.h"
268e3e3a7aSWarner Losh
278e3e3a7aSWarner Losh
288e3e3a7aSWarner Losh #if !defined(luai_verifycode)
290495ed39SKyle Evans #define luai_verifycode(L,f) /* empty */
308e3e3a7aSWarner Losh #endif
318e3e3a7aSWarner Losh
328e3e3a7aSWarner Losh
338e3e3a7aSWarner Losh typedef struct {
348e3e3a7aSWarner Losh lua_State *L;
358e3e3a7aSWarner Losh ZIO *Z;
368e3e3a7aSWarner Losh const char *name;
378e3e3a7aSWarner Losh } LoadState;
388e3e3a7aSWarner Losh
398e3e3a7aSWarner Losh
error(LoadState * S,const char * why)408e3e3a7aSWarner Losh static l_noret error (LoadState *S, const char *why) {
410495ed39SKyle Evans luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
428e3e3a7aSWarner Losh luaD_throw(S->L, LUA_ERRSYNTAX);
438e3e3a7aSWarner Losh }
448e3e3a7aSWarner Losh
458e3e3a7aSWarner Losh
468e3e3a7aSWarner Losh /*
470495ed39SKyle Evans ** All high-level loads go through loadVector; you can change it to
488e3e3a7aSWarner Losh ** adapt to the endianness of the input
498e3e3a7aSWarner Losh */
500495ed39SKyle Evans #define loadVector(S,b,n) loadBlock(S,b,(n)*sizeof((b)[0]))
518e3e3a7aSWarner Losh
loadBlock(LoadState * S,void * b,size_t size)520495ed39SKyle Evans static void loadBlock (LoadState *S, void *b, size_t size) {
538e3e3a7aSWarner Losh if (luaZ_read(S->Z, b, size) != 0)
540495ed39SKyle Evans error(S, "truncated chunk");
558e3e3a7aSWarner Losh }
568e3e3a7aSWarner Losh
578e3e3a7aSWarner Losh
580495ed39SKyle Evans #define loadVar(S,x) loadVector(S,&x,1)
598e3e3a7aSWarner Losh
608e3e3a7aSWarner Losh
loadByte(LoadState * S)610495ed39SKyle Evans static lu_byte loadByte (LoadState *S) {
620495ed39SKyle Evans int b = zgetc(S->Z);
630495ed39SKyle Evans if (b == EOZ)
640495ed39SKyle Evans error(S, "truncated chunk");
650495ed39SKyle Evans return cast_byte(b);
660495ed39SKyle Evans }
670495ed39SKyle Evans
680495ed39SKyle Evans
loadUnsigned(LoadState * S,size_t limit)690495ed39SKyle Evans static size_t loadUnsigned (LoadState *S, size_t limit) {
700495ed39SKyle Evans size_t x = 0;
710495ed39SKyle Evans int b;
720495ed39SKyle Evans limit >>= 7;
730495ed39SKyle Evans do {
740495ed39SKyle Evans b = loadByte(S);
750495ed39SKyle Evans if (x >= limit)
760495ed39SKyle Evans error(S, "integer overflow");
770495ed39SKyle Evans x = (x << 7) | (b & 0x7f);
780495ed39SKyle Evans } while ((b & 0x80) == 0);
798e3e3a7aSWarner Losh return x;
808e3e3a7aSWarner Losh }
818e3e3a7aSWarner Losh
828e3e3a7aSWarner Losh
loadSize(LoadState * S)830495ed39SKyle Evans static size_t loadSize (LoadState *S) {
840495ed39SKyle Evans return loadUnsigned(S, ~(size_t)0);
858e3e3a7aSWarner Losh }
868e3e3a7aSWarner Losh
878e3e3a7aSWarner Losh
loadInt(LoadState * S)880495ed39SKyle Evans static int loadInt (LoadState *S) {
890495ed39SKyle Evans return cast_int(loadUnsigned(S, INT_MAX));
900495ed39SKyle Evans }
910495ed39SKyle Evans
920495ed39SKyle Evans
loadNumber(LoadState * S)930495ed39SKyle Evans static lua_Number loadNumber (LoadState *S) {
948e3e3a7aSWarner Losh lua_Number x;
950495ed39SKyle Evans loadVar(S, x);
968e3e3a7aSWarner Losh return x;
978e3e3a7aSWarner Losh }
988e3e3a7aSWarner Losh
998e3e3a7aSWarner Losh
loadInteger(LoadState * S)1000495ed39SKyle Evans static lua_Integer loadInteger (LoadState *S) {
1018e3e3a7aSWarner Losh lua_Integer x;
1020495ed39SKyle Evans loadVar(S, x);
1038e3e3a7aSWarner Losh return x;
1048e3e3a7aSWarner Losh }
1058e3e3a7aSWarner Losh
1068e3e3a7aSWarner Losh
1070495ed39SKyle Evans /*
1080495ed39SKyle Evans ** Load a nullable string into prototype 'p'.
1090495ed39SKyle Evans */
loadStringN(LoadState * S,Proto * p)1100495ed39SKyle Evans static TString *loadStringN (LoadState *S, Proto *p) {
111bf9580a1SKyle Evans lua_State *L = S->L;
112bf9580a1SKyle Evans TString *ts;
1130495ed39SKyle Evans size_t size = loadSize(S);
1140495ed39SKyle Evans if (size == 0) /* no string? */
1158e3e3a7aSWarner Losh return NULL;
1168e3e3a7aSWarner Losh else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
1178e3e3a7aSWarner Losh char buff[LUAI_MAXSHORTLEN];
1180495ed39SKyle Evans loadVector(S, buff, size); /* load string into buffer */
1190495ed39SKyle Evans ts = luaS_newlstr(L, buff, size); /* create string */
1208e3e3a7aSWarner Losh }
1218e3e3a7aSWarner Losh else { /* long string */
1220495ed39SKyle Evans ts = luaS_createlngstrobj(L, size); /* create string */
123*a9490b81SWarner Losh setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
124bf9580a1SKyle Evans luaD_inctop(L);
1250495ed39SKyle Evans loadVector(S, getstr(ts), size); /* load directly in final place */
126*a9490b81SWarner Losh L->top.p--; /* pop string */
1278e3e3a7aSWarner Losh }
128bf9580a1SKyle Evans luaC_objbarrier(L, p, ts);
129bf9580a1SKyle Evans return ts;
1308e3e3a7aSWarner Losh }
1318e3e3a7aSWarner Losh
1328e3e3a7aSWarner Losh
1330495ed39SKyle Evans /*
1340495ed39SKyle Evans ** Load a non-nullable string into prototype 'p'.
1350495ed39SKyle Evans */
loadString(LoadState * S,Proto * p)1360495ed39SKyle Evans static TString *loadString (LoadState *S, Proto *p) {
1370495ed39SKyle Evans TString *st = loadStringN(S, p);
1380495ed39SKyle Evans if (st == NULL)
1390495ed39SKyle Evans error(S, "bad format for constant string");
1400495ed39SKyle Evans return st;
1418e3e3a7aSWarner Losh }
1428e3e3a7aSWarner Losh
1438e3e3a7aSWarner Losh
loadCode(LoadState * S,Proto * f)1440495ed39SKyle Evans static void loadCode (LoadState *S, Proto *f) {
1450495ed39SKyle Evans int n = loadInt(S);
1460495ed39SKyle Evans f->code = luaM_newvectorchecked(S->L, n, Instruction);
1470495ed39SKyle Evans f->sizecode = n;
1480495ed39SKyle Evans loadVector(S, f->code, n);
1490495ed39SKyle Evans }
1508e3e3a7aSWarner Losh
1518e3e3a7aSWarner Losh
1520495ed39SKyle Evans static void loadFunction(LoadState *S, Proto *f, TString *psource);
1530495ed39SKyle Evans
1540495ed39SKyle Evans
loadConstants(LoadState * S,Proto * f)1550495ed39SKyle Evans static void loadConstants (LoadState *S, Proto *f) {
1568e3e3a7aSWarner Losh int i;
1570495ed39SKyle Evans int n = loadInt(S);
1580495ed39SKyle Evans f->k = luaM_newvectorchecked(S->L, n, TValue);
1598e3e3a7aSWarner Losh f->sizek = n;
1608e3e3a7aSWarner Losh for (i = 0; i < n; i++)
1618e3e3a7aSWarner Losh setnilvalue(&f->k[i]);
1628e3e3a7aSWarner Losh for (i = 0; i < n; i++) {
1638e3e3a7aSWarner Losh TValue *o = &f->k[i];
1640495ed39SKyle Evans int t = loadByte(S);
1658e3e3a7aSWarner Losh switch (t) {
1660495ed39SKyle Evans case LUA_VNIL:
1678e3e3a7aSWarner Losh setnilvalue(o);
1688e3e3a7aSWarner Losh break;
1690495ed39SKyle Evans case LUA_VFALSE:
1700495ed39SKyle Evans setbfvalue(o);
1718e3e3a7aSWarner Losh break;
1720495ed39SKyle Evans case LUA_VTRUE:
1730495ed39SKyle Evans setbtvalue(o);
1748e3e3a7aSWarner Losh break;
1750495ed39SKyle Evans case LUA_VNUMFLT:
1760495ed39SKyle Evans setfltvalue(o, loadNumber(S));
1778e3e3a7aSWarner Losh break;
1780495ed39SKyle Evans case LUA_VNUMINT:
1790495ed39SKyle Evans setivalue(o, loadInteger(S));
1808e3e3a7aSWarner Losh break;
1810495ed39SKyle Evans case LUA_VSHRSTR:
1820495ed39SKyle Evans case LUA_VLNGSTR:
1830495ed39SKyle Evans setsvalue2n(S->L, o, loadString(S, f));
1840495ed39SKyle Evans break;
1850495ed39SKyle Evans default: lua_assert(0);
1868e3e3a7aSWarner Losh }
1878e3e3a7aSWarner Losh }
1888e3e3a7aSWarner Losh }
1898e3e3a7aSWarner Losh
1908e3e3a7aSWarner Losh
loadProtos(LoadState * S,Proto * f)1910495ed39SKyle Evans static void loadProtos (LoadState *S, Proto *f) {
1928e3e3a7aSWarner Losh int i;
1930495ed39SKyle Evans int n = loadInt(S);
1940495ed39SKyle Evans f->p = luaM_newvectorchecked(S->L, n, Proto *);
1958e3e3a7aSWarner Losh f->sizep = n;
1968e3e3a7aSWarner Losh for (i = 0; i < n; i++)
1978e3e3a7aSWarner Losh f->p[i] = NULL;
1988e3e3a7aSWarner Losh for (i = 0; i < n; i++) {
1998e3e3a7aSWarner Losh f->p[i] = luaF_newproto(S->L);
200bf9580a1SKyle Evans luaC_objbarrier(S->L, f, f->p[i]);
2010495ed39SKyle Evans loadFunction(S, f->p[i], f->source);
2028e3e3a7aSWarner Losh }
2038e3e3a7aSWarner Losh }
2048e3e3a7aSWarner Losh
2058e3e3a7aSWarner Losh
2060495ed39SKyle Evans /*
2070495ed39SKyle Evans ** Load the upvalues for a function. The names must be filled first,
2080495ed39SKyle Evans ** because the filling of the other fields can raise read errors and
2090495ed39SKyle Evans ** the creation of the error message can call an emergency collection;
2100495ed39SKyle Evans ** in that case all prototypes must be consistent for the GC.
2110495ed39SKyle Evans */
loadUpvalues(LoadState * S,Proto * f)2120495ed39SKyle Evans static void loadUpvalues (LoadState *S, Proto *f) {
2138e3e3a7aSWarner Losh int i, n;
2140495ed39SKyle Evans n = loadInt(S);
2150495ed39SKyle Evans f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
2168e3e3a7aSWarner Losh f->sizeupvalues = n;
2170495ed39SKyle Evans for (i = 0; i < n; i++) /* make array valid for GC */
2188e3e3a7aSWarner Losh f->upvalues[i].name = NULL;
2190495ed39SKyle Evans for (i = 0; i < n; i++) { /* following calls can raise errors */
2200495ed39SKyle Evans f->upvalues[i].instack = loadByte(S);
2210495ed39SKyle Evans f->upvalues[i].idx = loadByte(S);
2220495ed39SKyle Evans f->upvalues[i].kind = loadByte(S);
2238e3e3a7aSWarner Losh }
2248e3e3a7aSWarner Losh }
2258e3e3a7aSWarner Losh
2268e3e3a7aSWarner Losh
loadDebug(LoadState * S,Proto * f)2270495ed39SKyle Evans static void loadDebug (LoadState *S, Proto *f) {
2288e3e3a7aSWarner Losh int i, n;
2290495ed39SKyle Evans n = loadInt(S);
2300495ed39SKyle Evans f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
2318e3e3a7aSWarner Losh f->sizelineinfo = n;
2320495ed39SKyle Evans loadVector(S, f->lineinfo, n);
2330495ed39SKyle Evans n = loadInt(S);
2340495ed39SKyle Evans f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
2350495ed39SKyle Evans f->sizeabslineinfo = n;
2360495ed39SKyle Evans for (i = 0; i < n; i++) {
2370495ed39SKyle Evans f->abslineinfo[i].pc = loadInt(S);
2380495ed39SKyle Evans f->abslineinfo[i].line = loadInt(S);
2390495ed39SKyle Evans }
2400495ed39SKyle Evans n = loadInt(S);
2410495ed39SKyle Evans f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
2428e3e3a7aSWarner Losh f->sizelocvars = n;
2438e3e3a7aSWarner Losh for (i = 0; i < n; i++)
2448e3e3a7aSWarner Losh f->locvars[i].varname = NULL;
2458e3e3a7aSWarner Losh for (i = 0; i < n; i++) {
2460495ed39SKyle Evans f->locvars[i].varname = loadStringN(S, f);
2470495ed39SKyle Evans f->locvars[i].startpc = loadInt(S);
2480495ed39SKyle Evans f->locvars[i].endpc = loadInt(S);
2498e3e3a7aSWarner Losh }
2500495ed39SKyle Evans n = loadInt(S);
251*a9490b81SWarner Losh if (n != 0) /* does it have debug information? */
252*a9490b81SWarner Losh n = f->sizeupvalues; /* must be this many */
2538e3e3a7aSWarner Losh for (i = 0; i < n; i++)
2540495ed39SKyle Evans f->upvalues[i].name = loadStringN(S, f);
2558e3e3a7aSWarner Losh }
2568e3e3a7aSWarner Losh
2578e3e3a7aSWarner Losh
loadFunction(LoadState * S,Proto * f,TString * psource)2580495ed39SKyle Evans static void loadFunction (LoadState *S, Proto *f, TString *psource) {
2590495ed39SKyle Evans f->source = loadStringN(S, f);
2608e3e3a7aSWarner Losh if (f->source == NULL) /* no source in dump? */
2618e3e3a7aSWarner Losh f->source = psource; /* reuse parent's source */
2620495ed39SKyle Evans f->linedefined = loadInt(S);
2630495ed39SKyle Evans f->lastlinedefined = loadInt(S);
2640495ed39SKyle Evans f->numparams = loadByte(S);
2650495ed39SKyle Evans f->is_vararg = loadByte(S);
2660495ed39SKyle Evans f->maxstacksize = loadByte(S);
2670495ed39SKyle Evans loadCode(S, f);
2680495ed39SKyle Evans loadConstants(S, f);
2690495ed39SKyle Evans loadUpvalues(S, f);
2700495ed39SKyle Evans loadProtos(S, f);
2710495ed39SKyle Evans loadDebug(S, f);
2728e3e3a7aSWarner Losh }
2738e3e3a7aSWarner Losh
2748e3e3a7aSWarner Losh
checkliteral(LoadState * S,const char * s,const char * msg)2758e3e3a7aSWarner Losh static void checkliteral (LoadState *S, const char *s, const char *msg) {
2768e3e3a7aSWarner Losh char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
2778e3e3a7aSWarner Losh size_t len = strlen(s);
2780495ed39SKyle Evans loadVector(S, buff, len);
2798e3e3a7aSWarner Losh if (memcmp(s, buff, len) != 0)
2808e3e3a7aSWarner Losh error(S, msg);
2818e3e3a7aSWarner Losh }
2828e3e3a7aSWarner Losh
2838e3e3a7aSWarner Losh
fchecksize(LoadState * S,size_t size,const char * tname)2848e3e3a7aSWarner Losh static void fchecksize (LoadState *S, size_t size, const char *tname) {
2850495ed39SKyle Evans if (loadByte(S) != size)
2860495ed39SKyle Evans error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
2878e3e3a7aSWarner Losh }
2888e3e3a7aSWarner Losh
2898e3e3a7aSWarner Losh
2908e3e3a7aSWarner Losh #define checksize(S,t) fchecksize(S,sizeof(t),#t)
2918e3e3a7aSWarner Losh
checkHeader(LoadState * S)2928e3e3a7aSWarner Losh static void checkHeader (LoadState *S) {
2930495ed39SKyle Evans /* skip 1st char (already read and checked) */
2940495ed39SKyle Evans checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
2950495ed39SKyle Evans if (loadByte(S) != LUAC_VERSION)
2960495ed39SKyle Evans error(S, "version mismatch");
2970495ed39SKyle Evans if (loadByte(S) != LUAC_FORMAT)
2980495ed39SKyle Evans error(S, "format mismatch");
2990495ed39SKyle Evans checkliteral(S, LUAC_DATA, "corrupted chunk");
3008e3e3a7aSWarner Losh checksize(S, Instruction);
3018e3e3a7aSWarner Losh checksize(S, lua_Integer);
3028e3e3a7aSWarner Losh checksize(S, lua_Number);
3030495ed39SKyle Evans if (loadInteger(S) != LUAC_INT)
3040495ed39SKyle Evans error(S, "integer format mismatch");
3050495ed39SKyle Evans if (loadNumber(S) != LUAC_NUM)
3060495ed39SKyle Evans error(S, "float format mismatch");
3078e3e3a7aSWarner Losh }
3088e3e3a7aSWarner Losh
3098e3e3a7aSWarner Losh
3108e3e3a7aSWarner Losh /*
3110495ed39SKyle Evans ** Load precompiled chunk.
3128e3e3a7aSWarner Losh */
luaU_undump(lua_State * L,ZIO * Z,const char * name)3138e3e3a7aSWarner Losh LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
3148e3e3a7aSWarner Losh LoadState S;
3158e3e3a7aSWarner Losh LClosure *cl;
3168e3e3a7aSWarner Losh if (*name == '@' || *name == '=')
3178e3e3a7aSWarner Losh S.name = name + 1;
3188e3e3a7aSWarner Losh else if (*name == LUA_SIGNATURE[0])
3198e3e3a7aSWarner Losh S.name = "binary string";
3208e3e3a7aSWarner Losh else
3218e3e3a7aSWarner Losh S.name = name;
3228e3e3a7aSWarner Losh S.L = L;
3238e3e3a7aSWarner Losh S.Z = Z;
3248e3e3a7aSWarner Losh checkHeader(&S);
3250495ed39SKyle Evans cl = luaF_newLclosure(L, loadByte(&S));
326*a9490b81SWarner Losh setclLvalue2s(L, L->top.p, cl);
3278e3e3a7aSWarner Losh luaD_inctop(L);
3288e3e3a7aSWarner Losh cl->p = luaF_newproto(L);
329bf9580a1SKyle Evans luaC_objbarrier(L, cl, cl->p);
3300495ed39SKyle Evans loadFunction(&S, cl->p, NULL);
3318e3e3a7aSWarner Losh lua_assert(cl->nupvalues == cl->p->sizeupvalues);
3320495ed39SKyle Evans luai_verifycode(L, cl->p);
3338e3e3a7aSWarner Losh return cl;
3348e3e3a7aSWarner Losh }
3358e3e3a7aSWarner Losh
336