lua

A copy of the Lua development repository
Log | Files | Refs | README

lundump.c (10404B)


      1 /*
      2 ** $Id: lundump.c $
      3 ** load precompiled Lua chunks
      4 ** See Copyright Notice in lua.h
      5 */
      6 
      7 #define lundump_c
      8 #define LUA_CORE
      9 
     10 #include "lprefix.h"
     11 
     12 
     13 #include <limits.h>
     14 #include <string.h>
     15 
     16 #include "lua.h"
     17 
     18 #include "ldebug.h"
     19 #include "ldo.h"
     20 #include "lfunc.h"
     21 #include "lmem.h"
     22 #include "lobject.h"
     23 #include "lstring.h"
     24 #include "ltable.h"
     25 #include "lundump.h"
     26 #include "lzio.h"
     27 
     28 
     29 #if !defined(luai_verifycode)
     30 #define luai_verifycode(L,f)  /* empty */
     31 #endif
     32 
     33 
     34 typedef struct {
     35   lua_State *L;
     36   ZIO *Z;
     37   const char *name;
     38   Table *h;  /* list for string reuse */
     39   size_t offset;  /* current position relative to beginning of dump */
     40   lua_Integer nstr;  /* number of strings in the list */
     41   lu_byte fixed;  /* dump is fixed in memory */
     42 } LoadState;
     43 
     44 
     45 static l_noret error (LoadState *S, const char *why) {
     46   luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
     47   luaD_throw(S->L, LUA_ERRSYNTAX);
     48 }
     49 
     50 
     51 /*
     52 ** All high-level loads go through loadVector; you can change it to
     53 ** adapt to the endianness of the input
     54 */
     55 #define loadVector(S,b,n)	loadBlock(S,b,cast_sizet(n)*sizeof((b)[0]))
     56 
     57 static void loadBlock (LoadState *S, void *b, size_t size) {
     58   if (luaZ_read(S->Z, b, size) != 0)
     59     error(S, "truncated chunk");
     60   S->offset += size;
     61 }
     62 
     63 
     64 static void loadAlign (LoadState *S, unsigned align) {
     65   unsigned padding = align - cast_uint(S->offset % align);
     66   if (padding < align) {  /* (padding == align) means no padding */
     67     lua_Integer paddingContent;
     68     loadBlock(S, &paddingContent, padding);
     69     lua_assert(S->offset % align == 0);
     70   }
     71 }
     72 
     73 
     74 #define getaddr(S,n,t)	cast(t *, getaddr_(S,cast_sizet(n) * sizeof(t)))
     75 
     76 static const void *getaddr_ (LoadState *S, size_t size) {
     77   const void *block = luaZ_getaddr(S->Z, size);
     78   S->offset += size;
     79   if (block == NULL)
     80     error(S, "truncated fixed buffer");
     81   return block;
     82 }
     83 
     84 
     85 #define loadVar(S,x)		loadVector(S,&x,1)
     86 
     87 
     88 static lu_byte loadByte (LoadState *S) {
     89   int b = zgetc(S->Z);
     90   if (b == EOZ)
     91     error(S, "truncated chunk");
     92   S->offset++;
     93   return cast_byte(b);
     94 }
     95 
     96 
     97 static size_t loadVarint (LoadState *S, size_t limit) {
     98   size_t x = 0;
     99   int b;
    100   limit >>= 7;
    101   do {
    102     b = loadByte(S);
    103     if (x > limit)
    104       error(S, "integer overflow");
    105     x = (x << 7) | (b & 0x7f);
    106   } while ((b & 0x80) != 0);
    107   return x;
    108 }
    109 
    110 
    111 static size_t loadSize (LoadState *S) {
    112   return loadVarint(S, MAX_SIZE);
    113 }
    114 
    115 
    116 static int loadInt (LoadState *S) {
    117   return cast_int(loadVarint(S, cast_sizet(INT_MAX)));
    118 }
    119 
    120 
    121 
    122 static lua_Number loadNumber (LoadState *S) {
    123   lua_Number x;
    124   loadVar(S, x);
    125   return x;
    126 }
    127 
    128 
    129 static lua_Integer loadInteger (LoadState *S) {
    130   lua_Integer x;
    131   loadVar(S, x);
    132   return x;
    133 }
    134 
    135 
    136 /*
    137 ** Load a nullable string into slot 'sl' from prototype 'p'. The
    138 ** assignment to the slot and the barrier must be performed before any
    139 ** possible GC activity, to anchor the string. (Both 'loadVector' and
    140 ** 'luaH_setint' can call the GC.)
    141 */
    142 static void loadString (LoadState *S, Proto *p, TString **sl) {
    143   lua_State *L = S->L;
    144   TString *ts;
    145   TValue sv;
    146   size_t size = loadSize(S);
    147   if (size == 0) {  /* no string? */
    148     lua_assert(*sl == NULL);  /* must be prefilled */
    149     return;
    150   }
    151   else if (size == 1) {  /* previously saved string? */
    152     lua_Integer idx = cast(lua_Integer, loadSize(S));  /* get its index */
    153     TValue stv;
    154     luaH_getint(S->h, idx, &stv);  /* get its value */
    155     *sl = ts = tsvalue(&stv);
    156     luaC_objbarrier(L, p, ts);
    157     return;  /* do not save it again */
    158   }
    159   else if ((size -= 2) <= LUAI_MAXSHORTLEN) {  /* short string? */
    160     char buff[LUAI_MAXSHORTLEN + 1];  /* extra space for '\0' */
    161     loadVector(S, buff, size + 1);  /* load string into buffer */
    162     *sl = ts = luaS_newlstr(L, buff, size);  /* create string */
    163     luaC_objbarrier(L, p, ts);
    164   }
    165   else if (S->fixed) {  /* for a fixed buffer, use a fixed string */
    166     const char *s = getaddr(S, size + 1, char);  /* get content address */
    167     *sl = ts = luaS_newextlstr(L, s, size, NULL, NULL);
    168     luaC_objbarrier(L, p, ts);
    169   }
    170   else {  /* create internal copy */
    171     *sl = ts = luaS_createlngstrobj(L, size);  /* create string */
    172     luaC_objbarrier(L, p, ts);
    173     loadVector(S, getlngstr(ts), size + 1);  /* load directly in final place */
    174   }
    175   /* add string to list of saved strings */
    176   S->nstr++;
    177   setsvalue(L, &sv, ts);
    178   luaH_setint(L, S->h, S->nstr, &sv);
    179   luaC_objbarrierback(L, obj2gco(S->h), ts);
    180 }
    181 
    182 
    183 static void loadCode (LoadState *S, Proto *f) {
    184   int n = loadInt(S);
    185   loadAlign(S, sizeof(f->code[0]));
    186   if (S->fixed) {
    187     f->code = getaddr(S, n, Instruction);
    188     f->sizecode = n;
    189   }
    190   else {
    191     f->code = luaM_newvectorchecked(S->L, n, Instruction);
    192     f->sizecode = n;
    193     loadVector(S, f->code, n);
    194   }
    195 }
    196 
    197 
    198 static void loadFunction(LoadState *S, Proto *f);
    199 
    200 
    201 static void loadConstants (LoadState *S, Proto *f) {
    202   int i;
    203   int n = loadInt(S);
    204   f->k = luaM_newvectorchecked(S->L, n, TValue);
    205   f->sizek = n;
    206   for (i = 0; i < n; i++)
    207     setnilvalue(&f->k[i]);
    208   for (i = 0; i < n; i++) {
    209     TValue *o = &f->k[i];
    210     int t = loadByte(S);
    211     switch (t) {
    212       case LUA_VNIL:
    213         setnilvalue(o);
    214         break;
    215       case LUA_VFALSE:
    216         setbfvalue(o);
    217         break;
    218       case LUA_VTRUE:
    219         setbtvalue(o);
    220         break;
    221       case LUA_VNUMFLT:
    222         setfltvalue(o, loadNumber(S));
    223         break;
    224       case LUA_VNUMINT:
    225         setivalue(o, loadInteger(S));
    226         break;
    227       case LUA_VSHRSTR:
    228       case LUA_VLNGSTR: {
    229         lua_assert(f->source == NULL);
    230         loadString(S, f, &f->source);  /* use 'source' to anchor string */
    231         if (f->source == NULL)
    232           error(S, "bad format for constant string");
    233         setsvalue2n(S->L, o, f->source);  /* save it in the right place */
    234         f->source = NULL;
    235         break;
    236       }
    237       default: lua_assert(0);
    238     }
    239   }
    240 }
    241 
    242 
    243 static void loadProtos (LoadState *S, Proto *f) {
    244   int i;
    245   int n = loadInt(S);
    246   f->p = luaM_newvectorchecked(S->L, n, Proto *);
    247   f->sizep = n;
    248   for (i = 0; i < n; i++)
    249     f->p[i] = NULL;
    250   for (i = 0; i < n; i++) {
    251     f->p[i] = luaF_newproto(S->L);
    252     luaC_objbarrier(S->L, f, f->p[i]);
    253     loadFunction(S, f->p[i]);
    254   }
    255 }
    256 
    257 
    258 /*
    259 ** Load the upvalues for a function. The names must be filled first,
    260 ** because the filling of the other fields can raise read errors and
    261 ** the creation of the error message can call an emergency collection;
    262 ** in that case all prototypes must be consistent for the GC.
    263 */
    264 static void loadUpvalues (LoadState *S, Proto *f) {
    265   int i;
    266   int n = loadInt(S);
    267   f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
    268   f->sizeupvalues = n;
    269   for (i = 0; i < n; i++)  /* make array valid for GC */
    270     f->upvalues[i].name = NULL;
    271   for (i = 0; i < n; i++) {  /* following calls can raise errors */
    272     f->upvalues[i].instack = loadByte(S);
    273     f->upvalues[i].idx = loadByte(S);
    274     f->upvalues[i].kind = loadByte(S);
    275   }
    276 }
    277 
    278 
    279 static void loadDebug (LoadState *S, Proto *f) {
    280   int i;
    281   int n = loadInt(S);
    282   if (S->fixed) {
    283     f->lineinfo = getaddr(S, n, ls_byte);
    284     f->sizelineinfo = n;
    285   }
    286   else {
    287     f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
    288     f->sizelineinfo = n;
    289     loadVector(S, f->lineinfo, n);
    290   }
    291   n = loadInt(S);
    292   if (n > 0) {
    293     loadAlign(S, sizeof(int));
    294     if (S->fixed) {
    295       f->abslineinfo = getaddr(S, n, AbsLineInfo);
    296       f->sizeabslineinfo = n;
    297     }
    298     else {
    299       f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
    300       f->sizeabslineinfo = n;
    301       loadVector(S, f->abslineinfo, n);
    302     }
    303   }
    304   n = loadInt(S);
    305   f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
    306   f->sizelocvars = n;
    307   for (i = 0; i < n; i++)
    308     f->locvars[i].varname = NULL;
    309   for (i = 0; i < n; i++) {
    310     loadString(S, f, &f->locvars[i].varname);
    311     f->locvars[i].startpc = loadInt(S);
    312     f->locvars[i].endpc = loadInt(S);
    313   }
    314   n = loadInt(S);
    315   if (n != 0)  /* does it have debug information? */
    316     n = f->sizeupvalues;  /* must be this many */
    317   for (i = 0; i < n; i++)
    318     loadString(S, f, &f->upvalues[i].name);
    319 }
    320 
    321 
    322 static void loadFunction (LoadState *S, Proto *f) {
    323   f->linedefined = loadInt(S);
    324   f->lastlinedefined = loadInt(S);
    325   f->numparams = loadByte(S);
    326   f->flag = loadByte(S) & PF_ISVARARG;  /* get only the meaningful flags */
    327   if (S->fixed)
    328     f->flag |= PF_FIXED;  /* signal that code is fixed */
    329   f->maxstacksize = loadByte(S);
    330   loadCode(S, f);
    331   loadConstants(S, f);
    332   loadUpvalues(S, f);
    333   loadProtos(S, f);
    334   loadString(S, f, &f->source);
    335   loadDebug(S, f);
    336 }
    337 
    338 
    339 static void checkliteral (LoadState *S, const char *s, const char *msg) {
    340   char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
    341   size_t len = strlen(s);
    342   loadVector(S, buff, len);
    343   if (memcmp(s, buff, len) != 0)
    344     error(S, msg);
    345 }
    346 
    347 
    348 static void fchecksize (LoadState *S, size_t size, const char *tname) {
    349   if (loadByte(S) != size)
    350     error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
    351 }
    352 
    353 
    354 #define checksize(S,t)	fchecksize(S,sizeof(t),#t)
    355 
    356 static void checkHeader (LoadState *S) {
    357   /* skip 1st char (already read and checked) */
    358   checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
    359   if (loadByte(S) != LUAC_VERSION)
    360     error(S, "version mismatch");
    361   if (loadByte(S) != LUAC_FORMAT)
    362     error(S, "format mismatch");
    363   checkliteral(S, LUAC_DATA, "corrupted chunk");
    364   checksize(S, Instruction);
    365   checksize(S, lua_Integer);
    366   checksize(S, lua_Number);
    367   if (loadInteger(S) != LUAC_INT)
    368     error(S, "integer format mismatch");
    369   if (loadNumber(S) != LUAC_NUM)
    370     error(S, "float format mismatch");
    371 }
    372 
    373 
    374 /*
    375 ** Load precompiled chunk.
    376 */
    377 LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) {
    378   LoadState S;
    379   LClosure *cl;
    380   if (*name == '@' || *name == '=')
    381     S.name = name + 1;
    382   else if (*name == LUA_SIGNATURE[0])
    383     S.name = "binary string";
    384   else
    385     S.name = name;
    386   S.L = L;
    387   S.Z = Z;
    388   S.fixed = cast_byte(fixed);
    389   S.offset = 1;  /* fist byte was already read */
    390   checkHeader(&S);
    391   cl = luaF_newLclosure(L, loadByte(&S));
    392   setclLvalue2s(L, L->top.p, cl);
    393   luaD_inctop(L);
    394   S.h = luaH_new(L);  /* create list of saved strings */
    395   S.nstr = 0;
    396   sethvalue2s(L, L->top.p, S.h);  /* anchor it */
    397   luaD_inctop(L);
    398   cl->p = luaF_newproto(L);
    399   luaC_objbarrier(L, cl, cl->p);
    400   loadFunction(&S, cl->p);
    401   lua_assert(cl->nupvalues == cl->p->sizeupvalues);
    402   luai_verifycode(L, cl->p);
    403   L->top.p--;  /* pop table */
    404   return cl;
    405 }
    406