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