zombiezen.com/go/lua@v0.0.0-20231013005828-290725fb9140/internal/lua54/lundump.c (about)

     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 "lundump.h"
    25  #include "lzio.h"
    26  
    27  
    28  #if !defined(luai_verifycode)
    29  #define luai_verifycode(L,f)  /* empty */
    30  #endif
    31  
    32  
    33  typedef struct {
    34    lua_State *L;
    35    ZIO *Z;
    36    const char *name;
    37  } LoadState;
    38  
    39  
    40  static l_noret error (LoadState *S, const char *why) {
    41    luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
    42    luaD_throw(S->L, LUA_ERRSYNTAX);
    43  }
    44  
    45  
    46  /*
    47  ** All high-level loads go through loadVector; you can change it to
    48  ** adapt to the endianness of the input
    49  */
    50  #define loadVector(S,b,n)	loadBlock(S,b,(n)*sizeof((b)[0]))
    51  
    52  static void loadBlock (LoadState *S, void *b, size_t size) {
    53    if (luaZ_read(S->Z, b, size) != 0)
    54      error(S, "truncated chunk");
    55  }
    56  
    57  
    58  #define loadVar(S,x)		loadVector(S,&x,1)
    59  
    60  
    61  static lu_byte loadByte (LoadState *S) {
    62    int b = zgetc(S->Z);
    63    if (b == EOZ)
    64      error(S, "truncated chunk");
    65    return cast_byte(b);
    66  }
    67  
    68  
    69  static size_t loadUnsigned (LoadState *S, size_t limit) {
    70    size_t x = 0;
    71    int b;
    72    limit >>= 7;
    73    do {
    74      b = loadByte(S);
    75      if (x >= limit)
    76        error(S, "integer overflow");
    77      x = (x << 7) | (b & 0x7f);
    78    } while ((b & 0x80) == 0);
    79    return x;
    80  }
    81  
    82  
    83  static size_t loadSize (LoadState *S) {
    84    return loadUnsigned(S, ~(size_t)0);
    85  }
    86  
    87  
    88  static int loadInt (LoadState *S) {
    89    return cast_int(loadUnsigned(S, INT_MAX));
    90  }
    91  
    92  
    93  static lua_Number loadNumber (LoadState *S) {
    94    lua_Number x;
    95    loadVar(S, x);
    96    return x;
    97  }
    98  
    99  
   100  static lua_Integer loadInteger (LoadState *S) {
   101    lua_Integer x;
   102    loadVar(S, x);
   103    return x;
   104  }
   105  
   106  
   107  /*
   108  ** Load a nullable string into prototype 'p'.
   109  */
   110  static TString *loadStringN (LoadState *S, Proto *p) {
   111    lua_State *L = S->L;
   112    TString *ts;
   113    size_t size = loadSize(S);
   114    if (size == 0)  /* no string? */
   115      return NULL;
   116    else if (--size <= LUAI_MAXSHORTLEN) {  /* short string? */
   117      char buff[LUAI_MAXSHORTLEN];
   118      loadVector(S, buff, size);  /* load string into buffer */
   119      ts = luaS_newlstr(L, buff, size);  /* create string */
   120    }
   121    else {  /* long string */
   122      ts = luaS_createlngstrobj(L, size);  /* create string */
   123      setsvalue2s(L, L->top.p, ts);  /* anchor it ('loadVector' can GC) */
   124      luaD_inctop(L);
   125      loadVector(S, getstr(ts), size);  /* load directly in final place */
   126      L->top.p--;  /* pop string */
   127    }
   128    luaC_objbarrier(L, p, ts);
   129    return ts;
   130  }
   131  
   132  
   133  /*
   134  ** Load a non-nullable string into prototype 'p'.
   135  */
   136  static TString *loadString (LoadState *S, Proto *p) {
   137    TString *st = loadStringN(S, p);
   138    if (st == NULL)
   139      error(S, "bad format for constant string");
   140    return st;
   141  }
   142  
   143  
   144  static void loadCode (LoadState *S, Proto *f) {
   145    int n = loadInt(S);
   146    f->code = luaM_newvectorchecked(S->L, n, Instruction);
   147    f->sizecode = n;
   148    loadVector(S, f->code, n);
   149  }
   150  
   151  
   152  static void loadFunction(LoadState *S, Proto *f, TString *psource);
   153  
   154  
   155  static void loadConstants (LoadState *S, Proto *f) {
   156    int i;
   157    int n = loadInt(S);
   158    f->k = luaM_newvectorchecked(S->L, n, TValue);
   159    f->sizek = n;
   160    for (i = 0; i < n; i++)
   161      setnilvalue(&f->k[i]);
   162    for (i = 0; i < n; i++) {
   163      TValue *o = &f->k[i];
   164      int t = loadByte(S);
   165      switch (t) {
   166        case LUA_VNIL:
   167          setnilvalue(o);
   168          break;
   169        case LUA_VFALSE:
   170          setbfvalue(o);
   171          break;
   172        case LUA_VTRUE:
   173          setbtvalue(o);
   174          break;
   175        case LUA_VNUMFLT:
   176          setfltvalue(o, loadNumber(S));
   177          break;
   178        case LUA_VNUMINT:
   179          setivalue(o, loadInteger(S));
   180          break;
   181        case LUA_VSHRSTR:
   182        case LUA_VLNGSTR:
   183          setsvalue2n(S->L, o, loadString(S, f));
   184          break;
   185        default: lua_assert(0);
   186      }
   187    }
   188  }
   189  
   190  
   191  static void loadProtos (LoadState *S, Proto *f) {
   192    int i;
   193    int n = loadInt(S);
   194    f->p = luaM_newvectorchecked(S->L, n, Proto *);
   195    f->sizep = n;
   196    for (i = 0; i < n; i++)
   197      f->p[i] = NULL;
   198    for (i = 0; i < n; i++) {
   199      f->p[i] = luaF_newproto(S->L);
   200      luaC_objbarrier(S->L, f, f->p[i]);
   201      loadFunction(S, f->p[i], f->source);
   202    }
   203  }
   204  
   205  
   206  /*
   207  ** Load the upvalues for a function. The names must be filled first,
   208  ** because the filling of the other fields can raise read errors and
   209  ** the creation of the error message can call an emergency collection;
   210  ** in that case all prototypes must be consistent for the GC.
   211  */
   212  static void loadUpvalues (LoadState *S, Proto *f) {
   213    int i, n;
   214    n = loadInt(S);
   215    f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
   216    f->sizeupvalues = n;
   217    for (i = 0; i < n; i++)  /* make array valid for GC */
   218      f->upvalues[i].name = NULL;
   219    for (i = 0; i < n; i++) {  /* following calls can raise errors */
   220      f->upvalues[i].instack = loadByte(S);
   221      f->upvalues[i].idx = loadByte(S);
   222      f->upvalues[i].kind = loadByte(S);
   223    }
   224  }
   225  
   226  
   227  static void loadDebug (LoadState *S, Proto *f) {
   228    int i, n;
   229    n = loadInt(S);
   230    f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
   231    f->sizelineinfo = n;
   232    loadVector(S, f->lineinfo, n);
   233    n = loadInt(S);
   234    f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
   235    f->sizeabslineinfo = n;
   236    for (i = 0; i < n; i++) {
   237      f->abslineinfo[i].pc = loadInt(S);
   238      f->abslineinfo[i].line = loadInt(S);
   239    }
   240    n = loadInt(S);
   241    f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
   242    f->sizelocvars = n;
   243    for (i = 0; i < n; i++)
   244      f->locvars[i].varname = NULL;
   245    for (i = 0; i < n; i++) {
   246      f->locvars[i].varname = loadStringN(S, f);
   247      f->locvars[i].startpc = loadInt(S);
   248      f->locvars[i].endpc = loadInt(S);
   249    }
   250    n = loadInt(S);
   251    if (n != 0)  /* does it have debug information? */
   252      n = f->sizeupvalues;  /* must be this many */
   253    for (i = 0; i < n; i++)
   254      f->upvalues[i].name = loadStringN(S, f);
   255  }
   256  
   257  
   258  static void loadFunction (LoadState *S, Proto *f, TString *psource) {
   259    f->source = loadStringN(S, f);
   260    if (f->source == NULL)  /* no source in dump? */
   261      f->source = psource;  /* reuse parent's source */
   262    f->linedefined = loadInt(S);
   263    f->lastlinedefined = loadInt(S);
   264    f->numparams = loadByte(S);
   265    f->is_vararg = loadByte(S);
   266    f->maxstacksize = loadByte(S);
   267    loadCode(S, f);
   268    loadConstants(S, f);
   269    loadUpvalues(S, f);
   270    loadProtos(S, f);
   271    loadDebug(S, f);
   272  }
   273  
   274  
   275  static void checkliteral (LoadState *S, const char *s, const char *msg) {
   276    char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
   277    size_t len = strlen(s);
   278    loadVector(S, buff, len);
   279    if (memcmp(s, buff, len) != 0)
   280      error(S, msg);
   281  }
   282  
   283  
   284  static void fchecksize (LoadState *S, size_t size, const char *tname) {
   285    if (loadByte(S) != size)
   286      error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
   287  }
   288  
   289  
   290  #define checksize(S,t)	fchecksize(S,sizeof(t),#t)
   291  
   292  static void checkHeader (LoadState *S) {
   293    /* skip 1st char (already read and checked) */
   294    checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
   295    if (loadByte(S) != LUAC_VERSION)
   296      error(S, "version mismatch");
   297    if (loadByte(S) != LUAC_FORMAT)
   298      error(S, "format mismatch");
   299    checkliteral(S, LUAC_DATA, "corrupted chunk");
   300    checksize(S, Instruction);
   301    checksize(S, lua_Integer);
   302    checksize(S, lua_Number);
   303    if (loadInteger(S) != LUAC_INT)
   304      error(S, "integer format mismatch");
   305    if (loadNumber(S) != LUAC_NUM)
   306      error(S, "float format mismatch");
   307  }
   308  
   309  
   310  /*
   311  ** Load precompiled chunk.
   312  */
   313  LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
   314    LoadState S;
   315    LClosure *cl;
   316    if (*name == '@' || *name == '=')
   317      S.name = name + 1;
   318    else if (*name == LUA_SIGNATURE[0])
   319      S.name = "binary string";
   320    else
   321      S.name = name;
   322    S.L = L;
   323    S.Z = Z;
   324    checkHeader(&S);
   325    cl = luaF_newLclosure(L, loadByte(&S));
   326    setclLvalue2s(L, L->top.p, cl);
   327    luaD_inctop(L);
   328    cl->p = luaF_newproto(L);
   329    luaC_objbarrier(L, cl, cl->p);
   330    loadFunction(&S, cl->p, NULL);
   331    lua_assert(cl->nupvalues == cl->p->sizeupvalues);
   332    luai_verifycode(L, cl->p);
   333    return cl;
   334  }
   335