Coverage Report

Created: 2024-04-23 06:32

/src/testdir/build/lua-master/source/lundump.c
Line
Count
Source (jump to first uncovered line)
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 "ltable.h"
25
#include "lundump.h"
26
#include "lzio.h"
27
28
29
#if !defined(luai_verifycode)
30
#define luai_verifycode(L,f)  /* empty */
31
#endif
32
33
34
typedef struct {
35
  lua_State *L;
36
  ZIO *Z;
37
  const char *name;
38
  Table *h;  /* list for string reuse */
39
  lu_mem offset;  /* current position relative to beginning of dump */
40
  lua_Integer nstr;  /* number of strings in the list */
41
  lu_byte fixed;  /* dump is fixed in memory */
42
} LoadState;
43
44
45
0
static l_noret error (LoadState *S, const char *why) {
46
0
  luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
47
0
  luaD_throw(S->L, LUA_ERRSYNTAX);
48
0
}
49
50
51
/*
52
** All high-level loads go through loadVector; you can change it to
53
** adapt to the endianness of the input
54
*/
55
0
#define loadVector(S,b,n) loadBlock(S,b,(n)*sizeof((b)[0]))
56
57
0
static void loadBlock (LoadState *S, void *b, size_t size) {
58
0
  if (luaZ_read(S->Z, b, size) != 0)
59
0
    error(S, "truncated chunk");
60
0
  S->offset += size;
61
0
}
62
63
64
0
static void loadAlign (LoadState *S, int align) {
65
0
  int padding = align - (S->offset % align);
66
0
  if (padding < align) {  /* apd == align means no padding */
67
0
    lua_Integer paddingContent;
68
0
    loadBlock(S, &paddingContent, padding);
69
0
    lua_assert(S->offset % align == 0);
70
0
  }
71
0
}
72
73
74
0
#define getaddr(S,n,t)  cast(t *, getaddr_(S,(n) * sizeof(t)))
75
76
0
static const void *getaddr_ (LoadState *S, size_t size) {
77
0
  const void *block = luaZ_getaddr(S->Z, size);
78
0
  S->offset += size;
79
0
  if (block == NULL)
80
0
    error(S, "truncated fixed buffer");
81
0
  return block;
82
0
}
83
84
85
0
#define loadVar(S,x)    loadVector(S,&x,1)
86
87
88
0
static lu_byte loadByte (LoadState *S) {
89
0
  int b = zgetc(S->Z);
90
0
  if (b == EOZ)
91
0
    error(S, "truncated chunk");
92
0
  S->offset++;
93
0
  return cast_byte(b);
94
0
}
95
96
97
0
static size_t loadVarint (LoadState *S, size_t limit) {
98
0
  size_t x = 0;
99
0
  int b;
100
0
  limit >>= 7;
101
0
  do {
102
0
    b = loadByte(S);
103
0
    if (x > limit)
104
0
      error(S, "integer overflow");
105
0
    x = (x << 7) | (b & 0x7f);
106
0
  } while ((b & 0x80) != 0);
107
0
  return x;
108
0
}
109
110
111
0
static size_t loadSize (LoadState *S) {
112
0
  return loadVarint(S, MAX_SIZET);
113
0
}
114
115
116
0
static int loadInt (LoadState *S) {
117
0
  return cast_int(loadVarint(S, cast_sizet(INT_MAX)));
118
0
}
119
120
121
0
static lua_Number loadNumber (LoadState *S) {
122
0
  lua_Number x;
123
0
  loadVar(S, x);
124
0
  return x;
125
0
}
126
127
128
0
static lua_Integer loadInteger (LoadState *S) {
129
0
  lua_Integer x;
130
0
  loadVar(S, x);
131
0
  return x;
132
0
}
133
134
135
/*
136
** Load a nullable string into slot 'sl' from prototype 'p'. The
137
** assignment to the slot and the barrier must be performed before any
138
** possible GC activity, to anchor the string. (Both 'loadVector' and
139
** 'luaH_setint' can call the GC.)
140
*/
141
0
static void loadString (LoadState *S, Proto *p, TString **sl) {
142
0
  lua_State *L = S->L;
143
0
  TString *ts;
144
0
  TValue sv;
145
0
  size_t size = loadSize(S);
146
0
  if (size == 0) {  /* no string? */
147
0
    lua_assert(*sl == NULL);  /* must be prefilled */
148
0
    return;
149
0
  }
150
0
  else if (size == 1) {  /* previously saved string? */
151
0
    lua_Integer idx = cast(lua_Integer, loadSize(S));  /* get its index */
152
0
    TValue stv;
153
0
    luaH_getint(S->h, idx, &stv);  /* get its value */
154
0
    *sl = ts = tsvalue(&stv);
155
0
    luaC_objbarrier(L, p, ts);
156
0
    return;  /* do not save it again */
157
0
  }
158
0
  else if ((size -= 2) <= LUAI_MAXSHORTLEN) {  /* short string? */
159
0
    char buff[LUAI_MAXSHORTLEN + 1];  /* extra space for '\0' */
160
0
    loadVector(S, buff, size + 1);  /* load string into buffer */
161
0
    *sl = ts = luaS_newlstr(L, buff, size);  /* create string */
162
0
    luaC_objbarrier(L, p, ts);
163
0
  }
164
0
  else if (S->fixed) {  /* for a fixed buffer, use a fixed string */
165
0
    const char *s = getaddr(S, size + 1, char);  /* get content address */
166
0
    *sl = ts = luaS_newextlstr(L, s, size, NULL, NULL);
167
0
    luaC_objbarrier(L, p, ts);
168
0
  }
169
0
  else {  /* create internal copy */
170
0
    *sl = ts = luaS_createlngstrobj(L, size);  /* create string */
171
0
    luaC_objbarrier(L, p, ts);
172
0
    loadVector(S, getlngstr(ts), size + 1);  /* load directly in final place */
173
0
  }
174
  /* add string to list of saved strings */
175
0
  S->nstr++;
176
0
  setsvalue(L, &sv, ts);
177
0
  luaH_setint(L, S->h, S->nstr, &sv);
178
0
  luaC_objbarrierback(L, obj2gco(S->h), ts);
179
0
}
180
181
182
0
static void loadCode (LoadState *S, Proto *f) {
183
0
  int n = loadInt(S);
184
0
  loadAlign(S, sizeof(f->code[0]));
185
0
  if (S->fixed) {
186
0
    f->code = getaddr(S, n, Instruction);
187
0
    f->sizecode = n;
188
0
  }
189
0
  else {
190
0
    f->code = luaM_newvectorchecked(S->L, n, Instruction);
191
0
    f->sizecode = n;
192
0
    loadVector(S, f->code, n);
193
0
  }
194
0
}
195
196
197
static void loadFunction(LoadState *S, Proto *f);
198
199
200
0
static void loadConstants (LoadState *S, Proto *f) {
201
0
  int i;
202
0
  int n = loadInt(S);
203
0
  f->k = luaM_newvectorchecked(S->L, n, TValue);
204
0
  f->sizek = n;
205
0
  for (i = 0; i < n; i++)
206
0
    setnilvalue(&f->k[i]);
207
0
  for (i = 0; i < n; i++) {
208
0
    TValue *o = &f->k[i];
209
0
    int t = loadByte(S);
210
0
    switch (t) {
211
0
      case LUA_VNIL:
212
0
        setnilvalue(o);
213
0
        break;
214
0
      case LUA_VFALSE:
215
0
        setbfvalue(o);
216
0
        break;
217
0
      case LUA_VTRUE:
218
0
        setbtvalue(o);
219
0
        break;
220
0
      case LUA_VNUMFLT:
221
0
        setfltvalue(o, loadNumber(S));
222
0
        break;
223
0
      case LUA_VNUMINT:
224
0
        setivalue(o, loadInteger(S));
225
0
        break;
226
0
      case LUA_VSHRSTR:
227
0
      case LUA_VLNGSTR: {
228
0
        lua_assert(f->source == NULL);
229
0
        loadString(S, f, &f->source);  /* use 'source' to anchor string */
230
0
        if (f->source == NULL)
231
0
          error(S, "bad format for constant string");
232
0
        setsvalue2n(S->L, o, f->source);  /* save it in the right place */
233
0
        f->source = NULL;
234
0
        break;
235
0
      }
236
0
      default: lua_assert(0);
237
0
    }
238
0
  }
239
0
}
240
241
242
0
static void loadProtos (LoadState *S, Proto *f) {
243
0
  int i;
244
0
  int n = loadInt(S);
245
0
  f->p = luaM_newvectorchecked(S->L, n, Proto *);
246
0
  f->sizep = n;
247
0
  for (i = 0; i < n; i++)
248
0
    f->p[i] = NULL;
249
0
  for (i = 0; i < n; i++) {
250
0
    f->p[i] = luaF_newproto(S->L);
251
0
    luaC_objbarrier(S->L, f, f->p[i]);
252
0
    loadFunction(S, f->p[i]);
253
0
  }
254
0
}
255
256
257
/*
258
** Load the upvalues for a function. The names must be filled first,
259
** because the filling of the other fields can raise read errors and
260
** the creation of the error message can call an emergency collection;
261
** in that case all prototypes must be consistent for the GC.
262
*/
263
0
static void loadUpvalues (LoadState *S, Proto *f) {
264
0
  int i, n;
265
0
  n = loadInt(S);
266
0
  f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
267
0
  f->sizeupvalues = n;
268
0
  for (i = 0; i < n; i++)  /* make array valid for GC */
269
0
    f->upvalues[i].name = NULL;
270
0
  for (i = 0; i < n; i++) {  /* following calls can raise errors */
271
0
    f->upvalues[i].instack = loadByte(S);
272
0
    f->upvalues[i].idx = loadByte(S);
273
0
    f->upvalues[i].kind = loadByte(S);
274
0
  }
275
0
}
276
277
278
0
static void loadDebug (LoadState *S, Proto *f) {
279
0
  int i, n;
280
0
  n = loadInt(S);
281
0
  if (S->fixed) {
282
0
    f->lineinfo = getaddr(S, n, ls_byte);
283
0
    f->sizelineinfo = n;
284
0
  }
285
0
  else {
286
0
    f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
287
0
    f->sizelineinfo = n;
288
0
    loadVector(S, f->lineinfo, n);
289
0
  }
290
0
  n = loadInt(S);
291
0
  if (n > 0) {
292
0
    loadAlign(S, sizeof(int));
293
0
    if (S->fixed) {
294
0
      f->abslineinfo = getaddr(S, n, AbsLineInfo);
295
0
      f->sizeabslineinfo = n;
296
0
    }
297
0
    else {
298
0
      f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
299
0
      f->sizeabslineinfo = n;
300
0
      loadVector(S, f->abslineinfo, n);
301
0
    }
302
0
  }
303
0
  n = loadInt(S);
304
0
  f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
305
0
  f->sizelocvars = n;
306
0
  for (i = 0; i < n; i++)
307
0
    f->locvars[i].varname = NULL;
308
0
  for (i = 0; i < n; i++) {
309
0
    loadString(S, f, &f->locvars[i].varname);
310
0
    f->locvars[i].startpc = loadInt(S);
311
0
    f->locvars[i].endpc = loadInt(S);
312
0
  }
313
0
  n = loadInt(S);
314
0
  if (n != 0)  /* does it have debug information? */
315
0
    n = f->sizeupvalues;  /* must be this many */
316
0
  for (i = 0; i < n; i++)
317
0
    loadString(S, f, &f->upvalues[i].name);
318
0
}
319
320
321
0
static void loadFunction (LoadState *S, Proto *f) {
322
0
  f->linedefined = loadInt(S);
323
0
  f->lastlinedefined = loadInt(S);
324
0
  f->numparams = loadByte(S);
325
0
  f->flag = loadByte(S) & PF_ISVARARG;  /* get only the meaningful flags */
326
0
  if (S->fixed)
327
0
    f->flag |= PF_FIXED;  /* signal that code is fixed */
328
0
  f->maxstacksize = loadByte(S);
329
0
  loadCode(S, f);
330
0
  loadConstants(S, f);
331
0
  loadUpvalues(S, f);
332
0
  loadProtos(S, f);
333
0
  loadString(S, f, &f->source);
334
0
  loadDebug(S, f);
335
0
}
336
337
338
0
static void checkliteral (LoadState *S, const char *s, const char *msg) {
339
0
  char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
340
0
  size_t len = strlen(s);
341
0
  loadVector(S, buff, len);
342
0
  if (memcmp(s, buff, len) != 0)
343
0
    error(S, msg);
344
0
}
345
346
347
0
static void fchecksize (LoadState *S, size_t size, const char *tname) {
348
0
  if (loadByte(S) != size)
349
0
    error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
350
0
}
351
352
353
0
#define checksize(S,t)  fchecksize(S,sizeof(t),#t)
354
355
0
static void checkHeader (LoadState *S) {
356
  /* skip 1st char (already read and checked) */
357
0
  checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
358
0
  if (loadByte(S) != LUAC_VERSION)
359
0
    error(S, "version mismatch");
360
0
  if (loadByte(S) != LUAC_FORMAT)
361
0
    error(S, "format mismatch");
362
0
  checkliteral(S, LUAC_DATA, "corrupted chunk");
363
0
  checksize(S, Instruction);
364
0
  checksize(S, lua_Integer);
365
0
  checksize(S, lua_Number);
366
0
  if (loadInteger(S) != LUAC_INT)
367
0
    error(S, "integer format mismatch");
368
0
  if (loadNumber(S) != LUAC_NUM)
369
0
    error(S, "float format mismatch");
370
0
}
371
372
373
/*
374
** Load precompiled chunk.
375
*/
376
0
LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) {
377
0
  LoadState S;
378
0
  LClosure *cl;
379
0
  if (*name == '@' || *name == '=')
380
0
    S.name = name + 1;
381
0
  else if (*name == LUA_SIGNATURE[0])
382
0
    S.name = "binary string";
383
0
  else
384
0
    S.name = name;
385
0
  S.L = L;
386
0
  S.Z = Z;
387
0
  S.fixed = fixed;
388
0
  S.offset = 1;  /* fist byte was already read */
389
0
  checkHeader(&S);
390
0
  cl = luaF_newLclosure(L, loadByte(&S));
391
0
  setclLvalue2s(L, L->top.p, cl);
392
0
  luaD_inctop(L);
393
0
  S.h = luaH_new(L);  /* create list of saved strings */
394
0
  S.nstr = 0;
395
0
  sethvalue2s(L, L->top.p, S.h);  /* anchor it */
396
0
  luaD_inctop(L);
397
0
  cl->p = luaF_newproto(L);
398
0
  luaC_objbarrier(L, cl, cl->p);
399
0
  loadFunction(&S, cl->p);
400
0
  lua_assert(cl->nupvalues == cl->p->sizeupvalues);
401
0
  luai_verifycode(L, cl->p);
402
0
  L->top.p--;  /* pop table */
403
0
  return cl;
404
0
}
405