xref: /netbsd-src/external/mit/lua/dist/src/lundump.c (revision bdda0531de537df87feb2bf576711ab1be9b3675)
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