lundump.c revision 1.7
1/*	$NetBSD: lundump.c,v 1.7 2017/04/26 13:17:33 mbalmer Exp $	*/
2
3/*
4** Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp
5** load precompiled Lua chunks
6** See Copyright Notice in lua.h
7*/
8
9#define lundump_c
10#define LUA_CORE
11
12#include "lprefix.h"
13
14
15#ifndef _KERNEL
16#include <string.h>
17#endif /* _KERNEL */
18
19#include "lua.h"
20
21#include "ldebug.h"
22#include "ldo.h"
23#include "lfunc.h"
24#include "lmem.h"
25#include "lobject.h"
26#include "lstring.h"
27#include "lundump.h"
28#include "lzio.h"
29
30
31#if !defined(luai_verifycode)
32#define luai_verifycode(L,b,f)  /* empty */
33#endif
34
35
36typedef struct {
37  lua_State *L;
38  ZIO *Z;
39  const char *name;
40} LoadState;
41
42
43static l_noret error(LoadState *S, const char *why) {
44  luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why);
45  luaD_throw(S->L, LUA_ERRSYNTAX);
46}
47
48
49/*
50** All high-level loads go through LoadVector; you can change it to
51** adapt to the endianness of the input
52*/
53#define LoadVector(S,b,n)	LoadBlock(S,b,(n)*sizeof((b)[0]))
54
55static void LoadBlock (LoadState *S, void *b, size_t size) {
56  if (luaZ_read(S->Z, b, size) != 0)
57    error(S, "truncated");
58}
59
60
61#define LoadVar(S,x)		LoadVector(S,&x,1)
62
63
64static lu_byte LoadByte (LoadState *S) {
65  lu_byte x;
66  LoadVar(S, x);
67  return x;
68}
69
70
71static int LoadInt (LoadState *S) {
72  int x;
73  LoadVar(S, x);
74  return x;
75}
76
77
78static lua_Number LoadNumber (LoadState *S) {
79  lua_Number x;
80  LoadVar(S, x);
81  return x;
82}
83
84
85static lua_Integer LoadInteger (LoadState *S) {
86  lua_Integer x;
87  LoadVar(S, x);
88  return x;
89}
90
91
92static TString *LoadString (LoadState *S) {
93  size_t size = LoadByte(S);
94  if (size == 0xFF)
95    LoadVar(S, size);
96  if (size == 0)
97    return NULL;
98  else if (--size <= LUAI_MAXSHORTLEN) {  /* short string? */
99    char buff[LUAI_MAXSHORTLEN];
100    LoadVector(S, buff, size);
101    return luaS_newlstr(S->L, buff, size);
102  }
103  else {  /* long string */
104    TString *ts = luaS_createlngstrobj(S->L, size);
105    LoadVector(S, getstr(ts), size);  /* load directly in final place */
106    return ts;
107  }
108}
109
110
111static void LoadCode (LoadState *S, Proto *f) {
112  int n = LoadInt(S);
113  f->code = luaM_newvector(S->L, n, Instruction);
114  f->sizecode = n;
115  LoadVector(S, f->code, n);
116}
117
118
119static void LoadFunction(LoadState *S, Proto *f, TString *psource);
120
121
122static void LoadConstants (LoadState *S, Proto *f) {
123  int i;
124  int n = LoadInt(S);
125  f->k = luaM_newvector(S->L, n, TValue);
126  f->sizek = n;
127  for (i = 0; i < n; i++)
128    setnilvalue(&f->k[i]);
129  for (i = 0; i < n; i++) {
130    TValue *o = &f->k[i];
131    int t = LoadByte(S);
132    switch (t) {
133    case LUA_TNIL:
134      setnilvalue(o);
135      break;
136    case LUA_TBOOLEAN:
137      setbvalue(o, LoadByte(S));
138      break;
139#ifndef _KERNEL
140    case LUA_TNUMFLT:
141      setfltvalue(o, LoadNumber(S));
142      break;
143#endif /* _KERNEL */
144    case LUA_TNUMINT:
145      setivalue(o, LoadInteger(S));
146      break;
147    case LUA_TSHRSTR:
148    case LUA_TLNGSTR:
149      setsvalue2n(S->L, o, LoadString(S));
150      break;
151    default:
152      lua_assert(0);
153    }
154  }
155}
156
157
158static void LoadProtos (LoadState *S, Proto *f) {
159  int i;
160  int n = LoadInt(S);
161  f->p = luaM_newvector(S->L, n, Proto *);
162  f->sizep = n;
163  for (i = 0; i < n; i++)
164    f->p[i] = NULL;
165  for (i = 0; i < n; i++) {
166    f->p[i] = luaF_newproto(S->L);
167    LoadFunction(S, f->p[i], f->source);
168  }
169}
170
171
172static void LoadUpvalues (LoadState *S, Proto *f) {
173  int i, n;
174  n = LoadInt(S);
175  f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
176  f->sizeupvalues = n;
177  for (i = 0; i < n; i++)
178    f->upvalues[i].name = NULL;
179  for (i = 0; i < n; i++) {
180    f->upvalues[i].instack = LoadByte(S);
181    f->upvalues[i].idx = LoadByte(S);
182  }
183}
184
185
186static void LoadDebug (LoadState *S, Proto *f) {
187  int i, n;
188  n = LoadInt(S);
189  f->lineinfo = luaM_newvector(S->L, n, int);
190  f->sizelineinfo = n;
191  LoadVector(S, f->lineinfo, n);
192  n = LoadInt(S);
193  f->locvars = luaM_newvector(S->L, n, LocVar);
194  f->sizelocvars = n;
195  for (i = 0; i < n; i++)
196    f->locvars[i].varname = NULL;
197  for (i = 0; i < n; i++) {
198    f->locvars[i].varname = LoadString(S);
199    f->locvars[i].startpc = LoadInt(S);
200    f->locvars[i].endpc = LoadInt(S);
201  }
202  n = LoadInt(S);
203  for (i = 0; i < n; i++)
204    f->upvalues[i].name = LoadString(S);
205}
206
207
208static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
209  f->source = LoadString(S);
210  if (f->source == NULL)  /* no source in dump? */
211    f->source = psource;  /* reuse parent's source */
212  f->linedefined = LoadInt(S);
213  f->lastlinedefined = LoadInt(S);
214  f->numparams = LoadByte(S);
215  f->is_vararg = LoadByte(S);
216  f->maxstacksize = LoadByte(S);
217  LoadCode(S, f);
218  LoadConstants(S, f);
219  LoadUpvalues(S, f);
220  LoadProtos(S, f);
221  LoadDebug(S, f);
222}
223
224
225static void checkliteral (LoadState *S, const char *s, const char *msg) {
226  char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
227  size_t len = strlen(s);
228  LoadVector(S, buff, len);
229  if (memcmp(s, buff, len) != 0)
230    error(S, msg);
231}
232
233
234static void fchecksize (LoadState *S, size_t size, const char *tname) {
235  if (LoadByte(S) != size)
236    error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname));
237}
238
239
240#define checksize(S,t)	fchecksize(S,sizeof(t),#t)
241
242static void checkHeader (LoadState *S) {
243  checkliteral(S, LUA_SIGNATURE + 1, "not a");  /* 1st char already checked */
244  if (LoadByte(S) != LUAC_VERSION)
245    error(S, "version mismatch in");
246  if (LoadByte(S) != LUAC_FORMAT)
247    error(S, "format mismatch in");
248  checkliteral(S, LUAC_DATA, "corrupted");
249  checksize(S, int);
250  checksize(S, size_t);
251  checksize(S, Instruction);
252  checksize(S, lua_Integer);
253  checksize(S, lua_Number);
254  if (LoadInteger(S) != LUAC_INT)
255    error(S, "endianness mismatch in");
256  if (LoadNumber(S) != LUAC_NUM)
257    error(S, "float format mismatch in");
258}
259
260
261/*
262** load precompiled chunk
263*/
264LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
265  LoadState S;
266  LClosure *cl;
267  if (*name == '@' || *name == '=')
268    S.name = name + 1;
269  else if (*name == LUA_SIGNATURE[0])
270    S.name = "binary string";
271  else
272    S.name = name;
273  S.L = L;
274  S.Z = Z;
275  checkHeader(&S);
276  cl = luaF_newLclosure(L, LoadByte(&S));
277  setclLvalue(L, L->top, cl);
278  luaD_inctop(L);
279  cl->p = luaF_newproto(L);
280  LoadFunction(&S, cl->p, NULL);
281  lua_assert(cl->nupvalues == cl->p->sizeupvalues);
282  luai_verifycode(L, buff, cl->p);
283  return cl;
284}
285
286