xref: /netbsd-src/external/mit/lua/dist/src/lundump.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: lundump.c,v 1.8 2018/08/04 17:30:01 alnsn Exp $	*/
2 
3 /*
4 ** Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp
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 <string.h>
17 #endif /* _KERNEL */
18 
19 #include "lua.h"
20 
21 #include "ldebug.h"
22 #include "ldo.h"
23 #include "lfunc.h"
24 #include "lmem.h"
25 #include "lobject.h"
26 #include "lstring.h"
27 #include "lundump.h"
28 #include "lzio.h"
29 
30 
31 #if !defined(luai_verifycode)
32 #define luai_verifycode(L,b,f)  /* empty */
33 #endif
34 
35 
36 typedef struct {
37   lua_State *L;
38   ZIO *Z;
39   const char *name;
40 } LoadState;
41 
42 
43 static l_noret error(LoadState *S, const char *why) {
44   luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why);
45   luaD_throw(S->L, LUA_ERRSYNTAX);
46 }
47 
48 
49 /*
50 ** All high-level loads go through LoadVector; you can change it to
51 ** adapt to the endianness of the input
52 */
53 #define LoadVector(S,b,n)	LoadBlock(S,b,(n)*sizeof((b)[0]))
54 
55 static void LoadBlock (LoadState *S, void *b, size_t size) {
56   if (luaZ_read(S->Z, b, size) != 0)
57     error(S, "truncated");
58 }
59 
60 
61 #define LoadVar(S,x)		LoadVector(S,&x,1)
62 
63 
64 static lu_byte LoadByte (LoadState *S) {
65   lu_byte x;
66   LoadVar(S, x);
67   return x;
68 }
69 
70 
71 static int LoadInt (LoadState *S) {
72   int x;
73   LoadVar(S, x);
74   return x;
75 }
76 
77 
78 static lua_Number LoadNumber (LoadState *S) {
79   lua_Number x;
80   LoadVar(S, x);
81   return x;
82 }
83 
84 
85 static lua_Integer LoadInteger (LoadState *S) {
86   lua_Integer x;
87   LoadVar(S, x);
88   return x;
89 }
90 
91 
92 static TString *LoadString (LoadState *S) {
93   size_t size = LoadByte(S);
94   if (size == 0xFF)
95     LoadVar(S, size);
96   if (size == 0)
97     return NULL;
98   else if (--size <= LUAI_MAXSHORTLEN) {  /* short string? */
99     char buff[LUAI_MAXSHORTLEN];
100     LoadVector(S, buff, size);
101     return luaS_newlstr(S->L, buff, size);
102   }
103   else {  /* long string */
104     TString *ts = luaS_createlngstrobj(S->L, size);
105     LoadVector(S, getstr(ts), size);  /* load directly in final place */
106     return ts;
107   }
108 }
109 
110 
111 static void LoadCode (LoadState *S, Proto *f) {
112   int n = LoadInt(S);
113   f->code = luaM_newvector(S->L, n, Instruction);
114   f->sizecode = n;
115   LoadVector(S, f->code, n);
116 }
117 
118 
119 static void LoadFunction(LoadState *S, Proto *f, TString *psource);
120 
121 
122 static void LoadConstants (LoadState *S, Proto *f) {
123   int i;
124   int n = LoadInt(S);
125   f->k = luaM_newvector(S->L, n, TValue);
126   f->sizek = n;
127   for (i = 0; i < n; i++)
128     setnilvalue(&f->k[i]);
129   for (i = 0; i < n; i++) {
130     TValue *o = &f->k[i];
131     int t = LoadByte(S);
132     switch (t) {
133     case LUA_TNIL:
134       setnilvalue(o);
135       break;
136     case LUA_TBOOLEAN:
137       setbvalue(o, LoadByte(S));
138       break;
139 #ifndef _KERNEL
140     case LUA_TNUMFLT:
141       setfltvalue(o, LoadNumber(S));
142       break;
143 #endif /* _KERNEL */
144     case LUA_TNUMINT:
145       setivalue(o, LoadInteger(S));
146       break;
147     case LUA_TSHRSTR:
148     case LUA_TLNGSTR:
149       setsvalue2n(S->L, o, LoadString(S));
150       break;
151     default:
152       lua_assert(0);
153     }
154   }
155 }
156 
157 
158 static void LoadProtos (LoadState *S, Proto *f) {
159   int i;
160   int n = LoadInt(S);
161   f->p = luaM_newvector(S->L, n, Proto *);
162   f->sizep = n;
163   for (i = 0; i < n; i++)
164     f->p[i] = NULL;
165   for (i = 0; i < n; i++) {
166     f->p[i] = luaF_newproto(S->L);
167     LoadFunction(S, f->p[i], f->source);
168   }
169 }
170 
171 
172 static void LoadUpvalues (LoadState *S, Proto *f) {
173   int i, n;
174   n = LoadInt(S);
175   f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
176   f->sizeupvalues = n;
177   for (i = 0; i < n; i++)
178     f->upvalues[i].name = NULL;
179   for (i = 0; i < n; i++) {
180     f->upvalues[i].instack = LoadByte(S);
181     f->upvalues[i].idx = LoadByte(S);
182   }
183 }
184 
185 
186 static void LoadDebug (LoadState *S, Proto *f) {
187   int i, n;
188   n = LoadInt(S);
189   f->lineinfo = luaM_newvector(S->L, n, int);
190   f->sizelineinfo = n;
191   LoadVector(S, f->lineinfo, n);
192   n = LoadInt(S);
193   f->locvars = luaM_newvector(S->L, n, LocVar);
194   f->sizelocvars = n;
195   for (i = 0; i < n; i++)
196     f->locvars[i].varname = NULL;
197   for (i = 0; i < n; i++) {
198     f->locvars[i].varname = LoadString(S);
199     f->locvars[i].startpc = LoadInt(S);
200     f->locvars[i].endpc = LoadInt(S);
201   }
202   n = LoadInt(S);
203   for (i = 0; i < n; i++)
204     f->upvalues[i].name = LoadString(S);
205 }
206 
207 
208 static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
209   f->source = LoadString(S);
210   if (f->source == NULL)  /* no source in dump? */
211     f->source = psource;  /* reuse parent's source */
212   f->linedefined = LoadInt(S);
213   f->lastlinedefined = LoadInt(S);
214   f->numparams = LoadByte(S);
215   f->is_vararg = LoadByte(S);
216   f->maxstacksize = LoadByte(S);
217   LoadCode(S, f);
218   LoadConstants(S, f);
219   LoadUpvalues(S, f);
220   LoadProtos(S, f);
221   LoadDebug(S, f);
222 }
223 
224 
225 static void checkliteral (LoadState *S, const char *s, const char *msg) {
226   char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
227   size_t len = strlen(s);
228   LoadVector(S, buff, len);
229   if (memcmp(s, buff, len) != 0)
230     error(S, msg);
231 }
232 
233 
234 static void fchecksize (LoadState *S, size_t size, const char *tname) {
235   if (LoadByte(S) != size)
236     error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname));
237 }
238 
239 
240 #define checksize(S,t)	fchecksize(S,sizeof(t),#t)
241 
242 static void checkHeader (LoadState *S) {
243   checkliteral(S, LUA_SIGNATURE + 1, "not a");  /* 1st char already checked */
244   if (LoadByte(S) != LUAC_VERSION)
245     error(S, "version mismatch in");
246   if (LoadByte(S) != LUAC_FORMAT)
247     error(S, "format mismatch in");
248   checkliteral(S, LUAC_DATA, "corrupted");
249   checksize(S, int);
250   checksize(S, size_t);
251   checksize(S, Instruction);
252   checksize(S, lua_Integer);
253   checksize(S, lua_Number);
254   if (LoadInteger(S) != LUAC_INT)
255     error(S, "endianness mismatch in");
256   if (LoadNumber(S) != LUAC_NUM)
257     error(S, "float format mismatch in");
258 }
259 
260 
261 /*
262 ** load precompiled chunk
263 */
264 LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
265   LoadState S;
266   LClosure *cl;
267   if (*name == '@' || *name == '=')
268     S.name = name + 1;
269   else if (*name == LUA_SIGNATURE[0])
270     S.name = "binary string";
271   else
272     S.name = name;
273   S.L = L;
274   S.Z = Z;
275   checkHeader(&S);
276   cl = luaF_newLclosure(L, LoadByte(&S));
277   setclLvalue(L, L->top, cl);
278   luaD_inctop(L);
279   cl->p = luaF_newproto(L);
280   LoadFunction(&S, cl->p, NULL);
281   lua_assert(cl->nupvalues == cl->p->sizeupvalues);
282   luai_verifycode(L, buff, cl->p);
283   return cl;
284 }
285 
286