Coverage Report

Created: 2026-01-16 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/testdir/build/lua-master/source/ldump.c
Line
Count
Source
1
/*
2
** $Id: ldump.c $
3
** save precompiled Lua chunks
4
** See Copyright Notice in lua.h
5
*/
6
7
#define ldump_c
8
#define LUA_CORE
9
10
#include "lprefix.h"
11
12
13
#include <limits.h>
14
#include <stddef.h>
15
16
#include "lua.h"
17
18
#include "lapi.h"
19
#include "lgc.h"
20
#include "lobject.h"
21
#include "lstate.h"
22
#include "ltable.h"
23
#include "lundump.h"
24
25
26
typedef struct {
27
  lua_State *L;
28
  lua_Writer writer;
29
  void *data;
30
  size_t offset;  /* current position relative to beginning of dump */
31
  int strip;
32
  int status;
33
  Table *h;  /* table to track saved strings */
34
  lua_Unsigned nstr;  /* counter for counting saved strings */
35
} DumpState;
36
37
38
/*
39
** All high-level dumps go through dumpVector; you can change it to
40
** change the endianness of the result
41
*/
42
10.7M
#define dumpVector(D,v,n) dumpBlock(D,v,(n)*sizeof((v)[0]))
43
44
40.8k
#define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char))
45
46
47
/*
48
** Dump the block of memory pointed by 'b' with given 'size'.
49
** 'b' should not be NULL, except for the last call signaling the end
50
** of the dump.
51
*/
52
10.8M
static void dumpBlock (DumpState *D, const void *b, size_t size) {
53
10.8M
  if (D->status == 0) {  /* do not write anything after an error */
54
10.8M
    lua_unlock(D->L);
55
10.8M
    D->status = (*D->writer)(D->L, b, size, D->data);
56
10.8M
    lua_lock(D->L);
57
10.8M
    D->offset += size;
58
10.8M
  }
59
10.8M
}
60
61
62
/*
63
** Dump enough zeros to ensure that current position is a multiple of
64
** 'align'.
65
*/
66
150k
static void dumpAlign (DumpState *D, unsigned align) {
67
150k
  unsigned padding = align - cast_uint(D->offset % align);
68
150k
  if (padding < align) {  /* padding == align means no padding */
69
53.0k
    static lua_Integer paddingContent = 0;
70
53.0k
    lua_assert(align <= sizeof(lua_Integer));
71
53.0k
    dumpBlock(D, &paddingContent, padding);
72
53.0k
  }
73
150k
  lua_assert(D->offset % align == 0);
74
150k
}
75
76
77
6.12M
#define dumpVar(D,x)    dumpVector(D,&x,1)
78
79
80
3.53M
static void dumpByte (DumpState *D, int y) {
81
3.53M
  lu_byte x = (lu_byte)y;
82
3.53M
  dumpVar(D, x);
83
3.53M
}
84
85
86
/*
87
** size for 'dumpVarint' buffer: each byte can store up to 7 bits.
88
** (The "+6" rounds up the division.)
89
*/
90
4.93M
#define DIBS    ((l_numbits(lua_Unsigned) + 6) / 7)
91
92
/*
93
** Dumps an unsigned integer using the MSB Varint encoding
94
*/
95
4.11M
static void dumpVarint (DumpState *D, lua_Unsigned x) {
96
4.11M
  lu_byte buff[DIBS];
97
4.11M
  unsigned n = 1;
98
4.11M
  buff[DIBS - 1] = x & 0x7f;  /* fill least-significant byte */
99
4.93M
  while ((x >>= 7) != 0)  /* fill other bytes in reverse order */
100
4.11M
    buff[DIBS - (++n)] = cast_byte((x & 0x7f) | 0x80);
101
4.11M
  dumpVector(D, buff + DIBS - n, n);
102
4.11M
}
103
104
105
176k
static void dumpSize (DumpState *D, size_t sz) {
106
176k
  dumpVarint(D, cast(lua_Unsigned, sz));
107
176k
}
108
109
110
2.42M
static void dumpInt (DumpState *D, int x) {
111
2.42M
  lua_assert(x >= 0);
112
2.42M
  dumpVarint(D, cast_uint(x));
113
2.42M
}
114
115
116
2.50M
static void dumpNumber (DumpState *D, lua_Number x) {
117
2.50M
  dumpVar(D, x);
118
2.50M
}
119
120
121
/*
122
** Signed integers are coded to keep small values small. (Coding -1 as
123
** 0xfff...fff would use too many bytes to save a quite common value.)
124
** A non-negative x is coded as 2x; a negative x is coded as -2x - 1.
125
** (0 => 0; -1 => 1; 1 => 2; -2 => 3; 2 => 4; ...)
126
*/
127
39.6k
static void dumpInteger (DumpState *D, lua_Integer x) {
128
39.6k
  lua_Unsigned cx = (x >= 0) ? 2u * l_castS2U(x)
129
39.6k
                             : (2u * ~l_castS2U(x)) + 1;
130
39.6k
  dumpVarint(D, cx);
131
39.6k
}
132
133
134
/*
135
** Dump a String. First dump its "size":
136
** size==0 is followed by an index and means "reuse saved string with
137
** that index"; index==0 means NULL.
138
** size>=1 is followed by the string contents with real size==size-1 and
139
** means that string, which will be saved with the next available index.
140
** The real size does not include the ending '\0' (which is not dumped),
141
** so adding 1 to it cannot overflow a size_t.
142
*/
143
912k
static void dumpString (DumpState *D, TString *ts) {
144
912k
  if (ts == NULL) {
145
9.81k
    dumpVarint(D, 0);  /* will "reuse" NULL */
146
9.81k
    dumpVarint(D, 0);  /* special index for NULL */
147
9.81k
  }
148
903k
  else {
149
903k
    TValue idx;
150
903k
    int tag = luaH_getstr(D->h, ts, &idx);
151
903k
    if (!tagisempty(tag)) {  /* string already saved? */
152
726k
      dumpVarint(D, 0);  /* reuse a saved string */
153
726k
      dumpVarint(D, l_castS2U(ivalue(&idx)));  /* index of saved string */
154
726k
    }
155
176k
    else {  /* must write and save the string */
156
176k
      TValue key, value;  /* to save the string in the hash */
157
176k
      size_t size;
158
176k
      const char *s = getlstr(ts, size);
159
176k
      dumpSize(D, size + 1);
160
176k
      dumpVector(D, s, size + 1);  /* include ending '\0' */
161
176k
      D->nstr++;  /* one more saved string */
162
176k
      setsvalue(D->L, &key, ts);  /* the string is the key */
163
176k
      setivalue(&value, l_castU2S(D->nstr));  /* its index is the value */
164
176k
      luaH_set(D->L, D->h, &key, &value);  /* h[ts] = nstr */
165
      /* integer value does not need barrier */
166
176k
    }
167
903k
  }
168
912k
}
169
170
171
143k
static void dumpCode (DumpState *D, const Proto *f) {
172
143k
  dumpInt(D, f->sizecode);
173
143k
  dumpAlign(D, sizeof(f->code[0]));
174
143k
  lua_assert(f->code != NULL);
175
143k
  dumpVector(D, f->code, cast_uint(f->sizecode));
176
143k
}
177
178
179
static void dumpFunction (DumpState *D, const Proto *f);
180
181
143k
static void dumpConstants (DumpState *D, const Proto *f) {
182
143k
  int i;
183
143k
  int n = f->sizek;
184
143k
  dumpInt(D, n);
185
2.91M
  for (i = 0; i < n; i++) {
186
2.77M
    const TValue *o = &f->k[i];
187
2.77M
    int tt = ttypetag(o);
188
2.77M
    dumpByte(D, tt);
189
2.77M
    switch (tt) {
190
2.50M
      case LUA_VNUMFLT:
191
2.50M
        dumpNumber(D, fltvalue(o));
192
2.50M
        break;
193
39.6k
      case LUA_VNUMINT:
194
39.6k
        dumpInteger(D, ivalue(o));
195
39.6k
        break;
196
185k
      case LUA_VSHRSTR:
197
222k
      case LUA_VLNGSTR:
198
222k
        dumpString(D, tsvalue(o));
199
222k
        break;
200
4.55k
      default:
201
4.55k
        lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE);
202
2.77M
    }
203
2.77M
  }
204
143k
}
205
206
207
143k
static void dumpProtos (DumpState *D, const Proto *f) {
208
143k
  int i;
209
143k
  int n = f->sizep;
210
143k
  dumpInt(D, n);
211
266k
  for (i = 0; i < n; i++)
212
123k
    dumpFunction(D, f->p[i]);
213
143k
}
214
215
216
143k
static void dumpUpvalues (DumpState *D, const Proto *f) {
217
143k
  int i, n = f->sizeupvalues;
218
143k
  dumpInt(D, n);
219
206k
  for (i = 0; i < n; i++) {
220
63.2k
    dumpByte(D, f->upvalues[i].instack);
221
63.2k
    dumpByte(D, f->upvalues[i].idx);
222
63.2k
    dumpByte(D, f->upvalues[i].kind);
223
63.2k
  }
224
143k
}
225
226
227
143k
static void dumpDebug (DumpState *D, const Proto *f) {
228
143k
  int i, n;
229
143k
  n = (D->strip) ? 0 : f->sizelineinfo;
230
143k
  dumpInt(D, n);
231
143k
  if (f->lineinfo != NULL)
232
142k
    dumpVector(D, f->lineinfo, cast_uint(n));
233
143k
  n = (D->strip) ? 0 : f->sizeabslineinfo;
234
143k
  dumpInt(D, n);
235
143k
  if (n > 0) {
236
    /* 'abslineinfo' is an array of structures of int's */
237
6.95k
    dumpAlign(D, sizeof(int));
238
6.95k
    dumpVector(D, f->abslineinfo, cast_uint(n));
239
6.95k
  }
240
143k
  n = (D->strip) ? 0 : f->sizelocvars;
241
143k
  dumpInt(D, n);
242
637k
  for (i = 0; i < n; i++) {
243
494k
    dumpString(D, f->locvars[i].varname);
244
494k
    dumpInt(D, f->locvars[i].startpc);
245
494k
    dumpInt(D, f->locvars[i].endpc);
246
494k
  }
247
143k
  n = (D->strip) ? 0 : f->sizeupvalues;
248
143k
  dumpInt(D, n);
249
196k
  for (i = 0; i < n; i++)
250
52.6k
    dumpString(D, f->upvalues[i].name);
251
143k
}
252
253
254
143k
static void dumpFunction (DumpState *D, const Proto *f) {
255
143k
  dumpInt(D, f->linedefined);
256
143k
  dumpInt(D, f->lastlinedefined);
257
143k
  dumpByte(D, f->numparams);
258
143k
  dumpByte(D, f->flag);
259
143k
  dumpByte(D, f->maxstacksize);
260
143k
  dumpCode(D, f);
261
143k
  dumpConstants(D, f);
262
143k
  dumpUpvalues(D, f);
263
143k
  dumpProtos(D, f);
264
143k
  dumpString(D, D->strip ? NULL : f->source);
265
143k
  dumpDebug(D, f);
266
143k
}
267
268
269
#define dumpNumInfo(D, tvar, value)  \
270
81.6k
  { tvar i = value; dumpByte(D, sizeof(tvar)); dumpVar(D, i); }
271
272
273
20.4k
static void dumpHeader (DumpState *D) {
274
20.4k
  dumpLiteral(D, LUA_SIGNATURE);
275
20.4k
  dumpByte(D, LUAC_VERSION);
276
20.4k
  dumpByte(D, LUAC_FORMAT);
277
20.4k
  dumpLiteral(D, LUAC_DATA);
278
20.4k
  dumpNumInfo(D, int, LUAC_INT);
279
20.4k
  dumpNumInfo(D, Instruction, LUAC_INST);
280
20.4k
  dumpNumInfo(D, lua_Integer, LUAC_INT);
281
20.4k
  dumpNumInfo(D, lua_Number, LUAC_NUM);
282
20.4k
}
283
284
285
/*
286
** dump Lua function as precompiled chunk
287
*/
288
int luaU_dump (lua_State *L, const Proto *f, lua_Writer w, void *data,
289
20.4k
               int strip) {
290
20.4k
  DumpState D;
291
20.4k
  D.h = luaH_new(L);  /* aux. table to keep strings already dumped */
292
20.4k
  sethvalue2s(L, L->top.p, D.h);  /* anchor it */
293
20.4k
  L->top.p++;
294
20.4k
  D.L = L;
295
20.4k
  D.writer = w;
296
20.4k
  D.offset = 0;
297
20.4k
  D.data = data;
298
20.4k
  D.strip = strip;
299
20.4k
  D.status = 0;
300
20.4k
  D.nstr = 0;
301
20.4k
  dumpHeader(&D);
302
20.4k
  dumpByte(&D, f->sizeupvalues);
303
20.4k
  dumpFunction(&D, f);
304
  dumpBlock(&D, NULL, 0);  /* signal end of dump */
305
20.4k
  return D.status;
306
20.4k
}
307