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