Instead of an explicit value (field 'b'), true and false use different tag variants. This avoids reading an extra field and results in more direct code. (Most code that uses booleans needs to distinguish between true and false anyway.)
319 lines
6.9 KiB
C
319 lines
6.9 KiB
C
/*
|
|
** $Id: lundump.c $
|
|
** load precompiled Lua chunks
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
|
|
#define lundump_c
|
|
#define LUA_CORE
|
|
|
|
#include "lprefix.h"
|
|
|
|
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
|
|
#include "lua.h"
|
|
|
|
#include "ldebug.h"
|
|
#include "ldo.h"
|
|
#include "lfunc.h"
|
|
#include "lmem.h"
|
|
#include "lobject.h"
|
|
#include "lstring.h"
|
|
#include "lundump.h"
|
|
#include "lzio.h"
|
|
|
|
|
|
#if !defined(luai_verifycode)
|
|
#define luai_verifycode(L,b,f) /* empty */
|
|
#endif
|
|
|
|
|
|
typedef struct {
|
|
lua_State *L;
|
|
ZIO *Z;
|
|
const char *name;
|
|
} LoadState;
|
|
|
|
|
|
static l_noret error (LoadState *S, const char *why) {
|
|
luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
|
|
luaD_throw(S->L, LUA_ERRSYNTAX);
|
|
}
|
|
|
|
|
|
/*
|
|
** All high-level loads go through LoadVector; you can change it to
|
|
** adapt to the endianness of the input
|
|
*/
|
|
#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0]))
|
|
|
|
static void LoadBlock (LoadState *S, void *b, size_t size) {
|
|
if (luaZ_read(S->Z, b, size) != 0)
|
|
error(S, "truncated chunk");
|
|
}
|
|
|
|
|
|
#define LoadVar(S,x) LoadVector(S,&x,1)
|
|
|
|
|
|
static lu_byte LoadByte (LoadState *S) {
|
|
int b = zgetc(S->Z);
|
|
if (b == EOZ)
|
|
error(S, "truncated chunk");
|
|
return cast_byte(b);
|
|
}
|
|
|
|
|
|
static size_t LoadUnsigned (LoadState *S, size_t limit) {
|
|
size_t x = 0;
|
|
int b;
|
|
limit >>= 7;
|
|
do {
|
|
b = LoadByte(S);
|
|
if (x >= limit)
|
|
error(S, "integer overflow");
|
|
x = (x << 7) | (b & 0x7f);
|
|
} while ((b & 0x80) == 0);
|
|
return x;
|
|
}
|
|
|
|
|
|
static size_t LoadSize (LoadState *S) {
|
|
return LoadUnsigned(S, ~(size_t)0);
|
|
}
|
|
|
|
|
|
static int LoadInt (LoadState *S) {
|
|
return cast_int(LoadUnsigned(S, INT_MAX));
|
|
}
|
|
|
|
|
|
static lua_Number LoadNumber (LoadState *S) {
|
|
lua_Number x;
|
|
LoadVar(S, x);
|
|
return x;
|
|
}
|
|
|
|
|
|
static lua_Integer LoadInteger (LoadState *S) {
|
|
lua_Integer x;
|
|
LoadVar(S, x);
|
|
return x;
|
|
}
|
|
|
|
|
|
/*
|
|
** Load a nullable string
|
|
*/
|
|
static TString *LoadStringN (LoadState *S) {
|
|
size_t size = LoadSize(S);
|
|
if (size == 0)
|
|
return NULL;
|
|
else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
|
|
char buff[LUAI_MAXSHORTLEN];
|
|
LoadVector(S, buff, size);
|
|
return luaS_newlstr(S->L, buff, size);
|
|
}
|
|
else { /* long string */
|
|
TString *ts = luaS_createlngstrobj(S->L, size);
|
|
LoadVector(S, getstr(ts), size); /* load directly in final place */
|
|
return ts;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** Load a non-nullable string.
|
|
*/
|
|
static TString *LoadString (LoadState *S) {
|
|
TString *st = LoadStringN(S);
|
|
if (st == NULL)
|
|
error(S, "bad format for constant string");
|
|
return st;
|
|
}
|
|
|
|
|
|
static void LoadCode (LoadState *S, Proto *f) {
|
|
int n = LoadInt(S);
|
|
f->code = luaM_newvectorchecked(S->L, n, Instruction);
|
|
f->sizecode = n;
|
|
LoadVector(S, f->code, n);
|
|
}
|
|
|
|
|
|
static void LoadFunction(LoadState *S, Proto *f, TString *psource);
|
|
|
|
|
|
static void LoadConstants (LoadState *S, Proto *f) {
|
|
int i;
|
|
int n = LoadInt(S);
|
|
f->k = luaM_newvectorchecked(S->L, n, TValue);
|
|
f->sizek = n;
|
|
for (i = 0; i < n; i++)
|
|
setnilvalue(&f->k[i]);
|
|
for (i = 0; i < n; i++) {
|
|
TValue *o = &f->k[i];
|
|
int t = LoadByte(S);
|
|
switch (t) {
|
|
case LUA_TNIL:
|
|
setnilvalue(o);
|
|
break;
|
|
case LUA_TFALSE:
|
|
setbfvalue(o);
|
|
break;
|
|
case LUA_TTRUE:
|
|
setbtvalue(o);
|
|
break;
|
|
case LUA_TNUMFLT:
|
|
setfltvalue(o, LoadNumber(S));
|
|
break;
|
|
case LUA_TNUMINT:
|
|
setivalue(o, LoadInteger(S));
|
|
break;
|
|
case LUA_TSHRSTR:
|
|
case LUA_TLNGSTR:
|
|
setsvalue2n(S->L, o, LoadString(S));
|
|
break;
|
|
default: lua_assert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void LoadProtos (LoadState *S, Proto *f) {
|
|
int i;
|
|
int n = LoadInt(S);
|
|
f->p = luaM_newvectorchecked(S->L, n, Proto *);
|
|
f->sizep = n;
|
|
for (i = 0; i < n; i++)
|
|
f->p[i] = NULL;
|
|
for (i = 0; i < n; i++) {
|
|
f->p[i] = luaF_newproto(S->L);
|
|
LoadFunction(S, f->p[i], f->source);
|
|
}
|
|
}
|
|
|
|
|
|
static void LoadUpvalues (LoadState *S, Proto *f) {
|
|
int i, n;
|
|
n = LoadInt(S);
|
|
f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
|
|
f->sizeupvalues = n;
|
|
for (i = 0; i < n; i++) {
|
|
f->upvalues[i].name = NULL;
|
|
f->upvalues[i].instack = LoadByte(S);
|
|
f->upvalues[i].idx = LoadByte(S);
|
|
f->upvalues[i].kind = LoadByte(S);
|
|
}
|
|
}
|
|
|
|
|
|
static void LoadDebug (LoadState *S, Proto *f) {
|
|
int i, n;
|
|
n = LoadInt(S);
|
|
f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
|
|
f->sizelineinfo = n;
|
|
LoadVector(S, f->lineinfo, n);
|
|
n = LoadInt(S);
|
|
f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
|
|
f->sizeabslineinfo = n;
|
|
for (i = 0; i < n; i++) {
|
|
f->abslineinfo[i].pc = LoadInt(S);
|
|
f->abslineinfo[i].line = LoadInt(S);
|
|
}
|
|
n = LoadInt(S);
|
|
f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
|
|
f->sizelocvars = n;
|
|
for (i = 0; i < n; i++)
|
|
f->locvars[i].varname = NULL;
|
|
for (i = 0; i < n; i++) {
|
|
f->locvars[i].varname = LoadStringN(S);
|
|
f->locvars[i].startpc = LoadInt(S);
|
|
f->locvars[i].endpc = LoadInt(S);
|
|
}
|
|
n = LoadInt(S);
|
|
for (i = 0; i < n; i++)
|
|
f->upvalues[i].name = LoadStringN(S);
|
|
}
|
|
|
|
|
|
static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
|
|
f->source = LoadStringN(S);
|
|
if (f->source == NULL) /* no source in dump? */
|
|
f->source = psource; /* reuse parent's source */
|
|
f->linedefined = LoadInt(S);
|
|
f->lastlinedefined = LoadInt(S);
|
|
f->numparams = LoadByte(S);
|
|
f->is_vararg = LoadByte(S);
|
|
f->maxstacksize = LoadByte(S);
|
|
LoadCode(S, f);
|
|
LoadConstants(S, f);
|
|
LoadUpvalues(S, f);
|
|
LoadProtos(S, f);
|
|
LoadDebug(S, f);
|
|
}
|
|
|
|
|
|
static void checkliteral (LoadState *S, const char *s, const char *msg) {
|
|
char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
|
|
size_t len = strlen(s);
|
|
LoadVector(S, buff, len);
|
|
if (memcmp(s, buff, len) != 0)
|
|
error(S, msg);
|
|
}
|
|
|
|
|
|
static void fchecksize (LoadState *S, size_t size, const char *tname) {
|
|
if (LoadByte(S) != size)
|
|
error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
|
|
}
|
|
|
|
|
|
#define checksize(S,t) fchecksize(S,sizeof(t),#t)
|
|
|
|
static void checkHeader (LoadState *S) {
|
|
/* skip 1st char (already read and checked) */
|
|
checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
|
|
if (LoadInt(S) != LUAC_VERSION)
|
|
error(S, "version mismatch");
|
|
if (LoadByte(S) != LUAC_FORMAT)
|
|
error(S, "format mismatch");
|
|
checkliteral(S, LUAC_DATA, "corrupted chunk");
|
|
checksize(S, Instruction);
|
|
checksize(S, lua_Integer);
|
|
checksize(S, lua_Number);
|
|
if (LoadInteger(S) != LUAC_INT)
|
|
error(S, "integer format mismatch");
|
|
if (LoadNumber(S) != LUAC_NUM)
|
|
error(S, "float format mismatch");
|
|
}
|
|
|
|
|
|
/*
|
|
** load precompiled chunk
|
|
*/
|
|
LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
|
|
LoadState S;
|
|
LClosure *cl;
|
|
if (*name == '@' || *name == '=')
|
|
S.name = name + 1;
|
|
else if (*name == LUA_SIGNATURE[0])
|
|
S.name = "binary string";
|
|
else
|
|
S.name = name;
|
|
S.L = L;
|
|
S.Z = Z;
|
|
checkHeader(&S);
|
|
cl = luaF_newLclosure(L, LoadByte(&S));
|
|
setclLvalue2s(L, L->top, cl);
|
|
luaD_inctop(L);
|
|
cl->p = luaF_newproto(L);
|
|
LoadFunction(&S, cl->p, NULL);
|
|
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
|
luai_verifycode(L, buff, cl->p);
|
|
return cl;
|
|
}
|
|
|