mirror of
https://github.com/lua/lua
synced 2024-11-25 06:09:36 +03:00
75ea9ccbea
When "undumping" a long string, the function 'LoadVector' can call the reader function, which can run the garbage collector, which can collect the string being read. So, the string must be anchored during the call to 'LoadVector'. (This commit also fixes the identation in 'l_alloc'.)
288 lines
6.3 KiB
C
288 lines
6.3 KiB
C
/*
|
|
** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $
|
|
** load precompiled Lua chunks
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
|
|
#define lundump_c
|
|
#define LUA_CORE
|
|
|
|
#include "lprefix.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: %s precompiled chunk", 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");
|
|
}
|
|
|
|
|
|
#define LoadVar(S,x) LoadVector(S,&x,1)
|
|
|
|
|
|
static lu_byte LoadByte (LoadState *S) {
|
|
lu_byte x;
|
|
LoadVar(S, x);
|
|
return x;
|
|
}
|
|
|
|
|
|
static int LoadInt (LoadState *S) {
|
|
int x;
|
|
LoadVar(S, x);
|
|
return x;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
static TString *LoadString (LoadState *S, Proto *p) {
|
|
lua_State *L = S->L;
|
|
size_t size = LoadByte(S);
|
|
TString *ts;
|
|
if (size == 0xFF)
|
|
LoadVar(S, size);
|
|
if (size == 0)
|
|
return NULL;
|
|
else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
|
|
char buff[LUAI_MAXSHORTLEN];
|
|
LoadVector(S, buff, size);
|
|
ts = luaS_newlstr(L, buff, size);
|
|
}
|
|
else { /* long string */
|
|
ts = luaS_createlngstrobj(L, size);
|
|
setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
|
|
luaD_inctop(L);
|
|
LoadVector(S, getstr(ts), size); /* load directly in final place */
|
|
L->top--; /* pop string */
|
|
}
|
|
luaC_objbarrier(L, p, ts);
|
|
return ts;
|
|
}
|
|
|
|
|
|
static void LoadCode (LoadState *S, Proto *f) {
|
|
int n = LoadInt(S);
|
|
f->code = luaM_newvector(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_newvector(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_TBOOLEAN:
|
|
setbvalue(o, LoadByte(S));
|
|
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, f));
|
|
break;
|
|
default:
|
|
lua_assert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void LoadProtos (LoadState *S, Proto *f) {
|
|
int i;
|
|
int n = LoadInt(S);
|
|
f->p = luaM_newvector(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);
|
|
luaC_objbarrier(S->L, f, f->p[i]);
|
|
LoadFunction(S, f->p[i], f->source);
|
|
}
|
|
}
|
|
|
|
|
|
static void LoadUpvalues (LoadState *S, Proto *f) {
|
|
int i, n;
|
|
n = LoadInt(S);
|
|
f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
|
|
f->sizeupvalues = n;
|
|
for (i = 0; i < n; i++)
|
|
f->upvalues[i].name = NULL;
|
|
for (i = 0; i < n; i++) {
|
|
f->upvalues[i].instack = LoadByte(S);
|
|
f->upvalues[i].idx = LoadByte(S);
|
|
}
|
|
}
|
|
|
|
|
|
static void LoadDebug (LoadState *S, Proto *f) {
|
|
int i, n;
|
|
n = LoadInt(S);
|
|
f->lineinfo = luaM_newvector(S->L, n, int);
|
|
f->sizelineinfo = n;
|
|
LoadVector(S, f->lineinfo, n);
|
|
n = LoadInt(S);
|
|
f->locvars = luaM_newvector(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 = LoadString(S, f);
|
|
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 = LoadString(S, f);
|
|
}
|
|
|
|
|
|
static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
|
|
f->source = LoadString(S, f);
|
|
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 in", tname));
|
|
}
|
|
|
|
|
|
#define checksize(S,t) fchecksize(S,sizeof(t),#t)
|
|
|
|
static void checkHeader (LoadState *S) {
|
|
checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */
|
|
if (LoadByte(S) != LUAC_VERSION)
|
|
error(S, "version mismatch in");
|
|
if (LoadByte(S) != LUAC_FORMAT)
|
|
error(S, "format mismatch in");
|
|
checkliteral(S, LUAC_DATA, "corrupted");
|
|
checksize(S, int);
|
|
checksize(S, size_t);
|
|
checksize(S, Instruction);
|
|
checksize(S, lua_Integer);
|
|
checksize(S, lua_Number);
|
|
if (LoadInteger(S) != LUAC_INT)
|
|
error(S, "endianness mismatch in");
|
|
if (LoadNumber(S) != LUAC_NUM)
|
|
error(S, "float format mismatch in");
|
|
}
|
|
|
|
|
|
/*
|
|
** 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));
|
|
setclLvalue(L, L->top, cl);
|
|
luaD_inctop(L);
|
|
cl->p = luaF_newproto(L);
|
|
luaC_objbarrier(L, cl, cl->p);
|
|
LoadFunction(&S, cl->p, NULL);
|
|
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
|
luai_verifycode(L, buff, cl->p);
|
|
return cl;
|
|
}
|
|
|