1 /* $NetBSD: lundump.c,v 1.11 2023/06/08 21:12:08 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
37 typedef struct {
38 lua_State *L;
39 ZIO *Z;
40 const char *name;
41 } LoadState;
42
43
error(LoadState * S,const char * why)44 static 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
loadBlock(LoadState * S,void * b,size_t size)56 static 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
loadByte(LoadState * S)65 static 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
loadUnsigned(LoadState * S,size_t limit)73 static 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
loadSize(LoadState * S)87 static size_t loadSize (LoadState *S) {
88 return loadUnsigned(S, ~(size_t)0);
89 }
90
91
loadInt(LoadState * S)92 static int loadInt (LoadState *S) {
93 return cast_int(loadUnsigned(S, INT_MAX));
94 }
95
96
loadNumber(LoadState * S)97 static lua_Number loadNumber (LoadState *S) {
98 lua_Number x;
99 loadVar(S, x);
100 return x;
101 }
102
103
loadInteger(LoadState * S)104 static 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 */
loadStringN(LoadState * S,Proto * p)114 static 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.p, ts); /* anchor it ('loadVector' can GC) */
128 luaD_inctop(L);
129 loadVector(S, getstr(ts), size); /* load directly in final place */
130 L->top.p--; /* 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 */
loadString(LoadState * S,Proto * p)140 static 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
loadCode(LoadState * S,Proto * f)148 static 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
156 static void loadFunction(LoadState *S, Proto *f, TString *psource);
157
158
loadConstants(LoadState * S,Proto * f)159 static 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
loadProtos(LoadState * S,Proto * f)197 static 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 */
loadUpvalues(LoadState * S,Proto * f)218 static 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
loadDebug(LoadState * S,Proto * f)233 static 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 if (n != 0) /* does it have debug information? */
258 n = f->sizeupvalues; /* must be this many */
259 for (i = 0; i < n; i++)
260 f->upvalues[i].name = loadStringN(S, f);
261 }
262
263
loadFunction(LoadState * S,Proto * f,TString * psource)264 static void loadFunction (LoadState *S, Proto *f, TString *psource) {
265 f->source = loadStringN(S, f);
266 if (f->source == NULL) /* no source in dump? */
267 f->source = psource; /* reuse parent's source */
268 f->linedefined = loadInt(S);
269 f->lastlinedefined = loadInt(S);
270 f->numparams = loadByte(S);
271 f->is_vararg = loadByte(S);
272 f->maxstacksize = loadByte(S);
273 loadCode(S, f);
274 loadConstants(S, f);
275 loadUpvalues(S, f);
276 loadProtos(S, f);
277 loadDebug(S, f);
278 }
279
280
checkliteral(LoadState * S,const char * s,const char * msg)281 static void checkliteral (LoadState *S, const char *s, const char *msg) {
282 char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
283 size_t len = strlen(s);
284 loadVector(S, buff, len);
285 if (memcmp(s, buff, len) != 0)
286 error(S, msg);
287 }
288
289
fchecksize(LoadState * S,size_t size,const char * tname)290 static void fchecksize (LoadState *S, size_t size, const char *tname) {
291 if (loadByte(S) != size)
292 error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
293 }
294
295
296 #define checksize(S,t) fchecksize(S,sizeof(t),#t)
297
checkHeader(LoadState * S)298 static void checkHeader (LoadState *S) {
299 /* skip 1st char (already read and checked) */
300 checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
301 if (loadByte(S) != LUAC_VERSION)
302 error(S, "version mismatch");
303 if (loadByte(S) != LUAC_FORMAT)
304 error(S, "format mismatch");
305 checkliteral(S, LUAC_DATA, "corrupted chunk");
306 checksize(S, Instruction);
307 checksize(S, lua_Integer);
308 checksize(S, lua_Number);
309 if (loadInteger(S) != LUAC_INT)
310 error(S, "integer format mismatch");
311 if (loadNumber(S) != LUAC_NUM)
312 error(S, "float format mismatch");
313 }
314
315
316 /*
317 ** Load precompiled chunk.
318 */
luaU_undump(lua_State * L,ZIO * Z,const char * name)319 LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
320 LoadState S;
321 LClosure *cl;
322 if (*name == '@' || *name == '=')
323 S.name = name + 1;
324 else if (*name == LUA_SIGNATURE[0])
325 S.name = "binary string";
326 else
327 S.name = name;
328 S.L = L;
329 S.Z = Z;
330 checkHeader(&S);
331 cl = luaF_newLclosure(L, loadByte(&S));
332 setclLvalue2s(L, L->top.p, cl);
333 luaD_inctop(L);
334 cl->p = luaF_newproto(L);
335 luaC_objbarrier(L, cl, cl->p);
336 loadFunction(&S, cl->p, NULL);
337 lua_assert(cl->nupvalues == cl->p->sizeupvalues);
338 luai_verifycode(L, cl->p);
339 return cl;
340 }
341
342