Branch data Line data Source code
1 : : /*
2 : : ** $Id: lundump.c $
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 <limits.h>
14 : : #include <string.h>
15 : :
16 : : #include "lua.h"
17 : :
18 : : #include "ldebug.h"
19 : : #include "ldo.h"
20 : : #include "lfunc.h"
21 : : #include "lmem.h"
22 : : #include "lobject.h"
23 : : #include "lstring.h"
24 : : #include "lundump.h"
25 : : #include "lzio.h"
26 : :
27 : :
28 : : #if !defined(luai_verifycode)
29 : : #define luai_verifycode(L,f) /* empty */
30 : : #endif
31 : :
32 : :
33 : : typedef struct {
34 : : lua_State *L;
35 : : ZIO *Z;
36 : : const char *name;
37 : : } LoadState;
38 : :
39 : :
40 : 0 : static l_noret error (LoadState *S, const char *why) {
41 : 0 : luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
42 : 0 : luaD_throw(S->L, LUA_ERRSYNTAX);
43 : : }
44 : :
45 : :
46 : : /*
47 : : ** All high-level loads go through loadVector; you can change it to
48 : : ** adapt to the endianness of the input
49 : : */
50 : : #define loadVector(S,b,n) loadBlock(S,b,(n)*sizeof((b)[0]))
51 : :
52 : 0 : static void loadBlock (LoadState *S, void *b, size_t size) {
53 [ # # ]: 0 : if (luaZ_read(S->Z, b, size) != 0)
54 : 0 : error(S, "truncated chunk");
55 : 0 : }
56 : :
57 : :
58 : : #define loadVar(S,x) loadVector(S,&x,1)
59 : :
60 : :
61 : 0 : static lu_byte loadByte (LoadState *S) {
62 [ # # ]: 0 : int b = zgetc(S->Z);
63 [ # # ]: 0 : if (b == EOZ)
64 : 0 : error(S, "truncated chunk");
65 : 0 : return cast_byte(b);
66 : : }
67 : :
68 : :
69 : 0 : static size_t loadUnsigned (LoadState *S, size_t limit) {
70 : 0 : size_t x = 0;
71 : : int b;
72 : 0 : limit >>= 7;
73 : 0 : do {
74 : 0 : b = loadByte(S);
75 [ # # ]: 0 : if (x >= limit)
76 : 0 : error(S, "integer overflow");
77 : 0 : x = (x << 7) | (b & 0x7f);
78 [ # # ]: 0 : } while ((b & 0x80) == 0);
79 : 0 : return x;
80 : : }
81 : :
82 : :
83 : 0 : static size_t loadSize (LoadState *S) {
84 : 0 : return loadUnsigned(S, ~(size_t)0);
85 : : }
86 : :
87 : :
88 : 0 : static int loadInt (LoadState *S) {
89 : 0 : return cast_int(loadUnsigned(S, INT_MAX));
90 : : }
91 : :
92 : :
93 : 0 : static lua_Number loadNumber (LoadState *S) {
94 : : lua_Number x;
95 : 0 : loadVar(S, x);
96 : 0 : return x;
97 : : }
98 : :
99 : :
100 : 0 : static lua_Integer loadInteger (LoadState *S) {
101 : : lua_Integer x;
102 : 0 : loadVar(S, x);
103 : 0 : return x;
104 : : }
105 : :
106 : :
107 : : /*
108 : : ** Load a nullable string into prototype 'p'.
109 : : */
110 : 0 : static TString *loadStringN (LoadState *S, Proto *p) {
111 : 0 : lua_State *L = S->L;
112 : : TString *ts;
113 : 0 : size_t size = loadSize(S);
114 [ # # ]: 0 : if (size == 0) /* no string? */
115 : 0 : return NULL;
116 [ # # ]: 0 : else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
117 : : char buff[LUAI_MAXSHORTLEN];
118 : 0 : loadVector(S, buff, size); /* load string into buffer */
119 : 0 : ts = luaS_newlstr(L, buff, size); /* create string */
120 : 0 : }
121 : : else { /* long string */
122 : 0 : ts = luaS_createlngstrobj(L, size); /* create string */
123 : 0 : setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
124 : 0 : luaD_inctop(L);
125 : 0 : loadVector(S, getstr(ts), size); /* load directly in final place */
126 : 0 : L->top--; /* pop string */
127 : : }
128 [ # # # # ]: 0 : luaC_objbarrier(L, p, ts);
129 : 0 : return ts;
130 : 0 : }
131 : :
132 : :
133 : : /*
134 : : ** Load a non-nullable string into prototype 'p'.
135 : : */
136 : 0 : static TString *loadString (LoadState *S, Proto *p) {
137 : 0 : TString *st = loadStringN(S, p);
138 [ # # ]: 0 : if (st == NULL)
139 : 0 : error(S, "bad format for constant string");
140 : 0 : return st;
141 : : }
142 : :
143 : :
144 : 0 : static void loadCode (LoadState *S, Proto *f) {
145 : 0 : int n = loadInt(S);
146 : 0 : f->code = luaM_newvectorchecked(S->L, n, Instruction);
147 : 0 : f->sizecode = n;
148 : 0 : loadVector(S, f->code, n);
149 : 0 : }
150 : :
151 : :
152 : : static void loadFunction(LoadState *S, Proto *f, TString *psource);
153 : :
154 : :
155 : 0 : static void loadConstants (LoadState *S, Proto *f) {
156 : : int i;
157 : 0 : int n = loadInt(S);
158 : 0 : f->k = luaM_newvectorchecked(S->L, n, TValue);
159 : 0 : f->sizek = n;
160 [ # # ]: 0 : for (i = 0; i < n; i++)
161 : 0 : setnilvalue(&f->k[i]);
162 [ # # ]: 0 : for (i = 0; i < n; i++) {
163 : 0 : TValue *o = &f->k[i];
164 : 0 : int t = loadByte(S);
165 [ # # # # : 0 : switch (t) {
# # # ]
166 : : case LUA_VNIL:
167 : 0 : setnilvalue(o);
168 : 0 : break;
169 : : case LUA_VFALSE:
170 : 0 : setbfvalue(o);
171 : 0 : break;
172 : : case LUA_VTRUE:
173 : 0 : setbtvalue(o);
174 : 0 : break;
175 : : case LUA_VNUMFLT:
176 : 0 : setfltvalue(o, loadNumber(S));
177 : 0 : break;
178 : : case LUA_VNUMINT:
179 : 0 : setivalue(o, loadInteger(S));
180 : 0 : break;
181 : : case LUA_VSHRSTR:
182 : : case LUA_VLNGSTR:
183 : 0 : setsvalue2n(S->L, o, loadString(S, f));
184 : 0 : break;
185 : : default: lua_assert(0);
186 : 0 : }
187 : 0 : }
188 : 0 : }
189 : :
190 : :
191 : 0 : static void loadProtos (LoadState *S, Proto *f) {
192 : : int i;
193 : 0 : int n = loadInt(S);
194 : 0 : f->p = luaM_newvectorchecked(S->L, n, Proto *);
195 : 0 : f->sizep = n;
196 [ # # ]: 0 : for (i = 0; i < n; i++)
197 : 0 : f->p[i] = NULL;
198 [ # # ]: 0 : for (i = 0; i < n; i++) {
199 : 0 : f->p[i] = luaF_newproto(S->L);
200 [ # # # # ]: 0 : luaC_objbarrier(S->L, f, f->p[i]);
201 : 0 : loadFunction(S, f->p[i], f->source);
202 : 0 : }
203 : 0 : }
204 : :
205 : :
206 : : /*
207 : : ** Load the upvalues for a function. The names must be filled first,
208 : : ** because the filling of the other fields can raise read errors and
209 : : ** the creation of the error message can call an emergency collection;
210 : : ** in that case all prototypes must be consistent for the GC.
211 : : */
212 : 0 : static void loadUpvalues (LoadState *S, Proto *f) {
213 : : int i, n;
214 : 0 : n = loadInt(S);
215 : 0 : f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
216 : 0 : f->sizeupvalues = n;
217 [ # # ]: 0 : for (i = 0; i < n; i++) /* make array valid for GC */
218 : 0 : f->upvalues[i].name = NULL;
219 [ # # ]: 0 : for (i = 0; i < n; i++) { /* following calls can raise errors */
220 : 0 : f->upvalues[i].instack = loadByte(S);
221 : 0 : f->upvalues[i].idx = loadByte(S);
222 : 0 : f->upvalues[i].kind = loadByte(S);
223 : 0 : }
224 : 0 : }
225 : :
226 : :
227 : 0 : static void loadDebug (LoadState *S, Proto *f) {
228 : : int i, n;
229 : 0 : n = loadInt(S);
230 : 0 : f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
231 : 0 : f->sizelineinfo = n;
232 : 0 : loadVector(S, f->lineinfo, n);
233 : 0 : n = loadInt(S);
234 : 0 : f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
235 : 0 : f->sizeabslineinfo = n;
236 [ # # ]: 0 : for (i = 0; i < n; i++) {
237 : 0 : f->abslineinfo[i].pc = loadInt(S);
238 : 0 : f->abslineinfo[i].line = loadInt(S);
239 : 0 : }
240 : 0 : n = loadInt(S);
241 : 0 : f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
242 : 0 : f->sizelocvars = n;
243 [ # # ]: 0 : for (i = 0; i < n; i++)
244 : 0 : f->locvars[i].varname = NULL;
245 [ # # ]: 0 : for (i = 0; i < n; i++) {
246 : 0 : f->locvars[i].varname = loadStringN(S, f);
247 : 0 : f->locvars[i].startpc = loadInt(S);
248 : 0 : f->locvars[i].endpc = loadInt(S);
249 : 0 : }
250 : 0 : n = loadInt(S);
251 [ # # ]: 0 : for (i = 0; i < n; i++)
252 : 0 : f->upvalues[i].name = loadStringN(S, f);
253 : 0 : }
254 : :
255 : :
256 : 0 : static void loadFunction (LoadState *S, Proto *f, TString *psource) {
257 : 0 : f->source = loadStringN(S, f);
258 [ # # ]: 0 : if (f->source == NULL) /* no source in dump? */
259 : 0 : f->source = psource; /* reuse parent's source */
260 : 0 : f->linedefined = loadInt(S);
261 : 0 : f->lastlinedefined = loadInt(S);
262 : 0 : f->numparams = loadByte(S);
263 : 0 : f->is_vararg = loadByte(S);
264 : 0 : f->maxstacksize = loadByte(S);
265 : 0 : loadCode(S, f);
266 : 0 : loadConstants(S, f);
267 : 0 : loadUpvalues(S, f);
268 : 0 : loadProtos(S, f);
269 : 0 : loadDebug(S, f);
270 : 0 : }
271 : :
272 : :
273 : 0 : static void checkliteral (LoadState *S, const char *s, const char *msg) {
274 : : char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
275 : 0 : size_t len = strlen(s);
276 : 0 : loadVector(S, buff, len);
277 [ # # ]: 0 : if (memcmp(s, buff, len) != 0)
278 : 0 : error(S, msg);
279 : 0 : }
280 : :
281 : :
282 : 0 : static void fchecksize (LoadState *S, size_t size, const char *tname) {
283 [ # # ]: 0 : if (loadByte(S) != size)
284 : 0 : error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
285 : 0 : }
286 : :
287 : :
288 : : #define checksize(S,t) fchecksize(S,sizeof(t),#t)
289 : :
290 : 0 : static void checkHeader (LoadState *S) {
291 : : /* skip 1st char (already read and checked) */
292 : 0 : checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
293 [ # # ]: 0 : if (loadByte(S) != LUAC_VERSION)
294 : 0 : error(S, "version mismatch");
295 [ # # ]: 0 : if (loadByte(S) != LUAC_FORMAT)
296 : 0 : error(S, "format mismatch");
297 : 0 : checkliteral(S, LUAC_DATA, "corrupted chunk");
298 : 0 : checksize(S, Instruction);
299 : 0 : checksize(S, lua_Integer);
300 : 0 : checksize(S, lua_Number);
301 [ # # ]: 0 : if (loadInteger(S) != LUAC_INT)
302 : 0 : error(S, "integer format mismatch");
303 [ # # ]: 0 : if (loadNumber(S) != LUAC_NUM)
304 : 0 : error(S, "float format mismatch");
305 : 0 : }
306 : :
307 : :
308 : : /*
309 : : ** Load precompiled chunk.
310 : : */
311 : 0 : LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
312 : : LoadState S;
313 : : LClosure *cl;
314 [ # # # # ]: 0 : if (*name == '@' || *name == '=')
315 : 0 : S.name = name + 1;
316 [ # # ]: 0 : else if (*name == LUA_SIGNATURE[0])
317 : 0 : S.name = "binary string";
318 : : else
319 : 0 : S.name = name;
320 : 0 : S.L = L;
321 : 0 : S.Z = Z;
322 : 0 : checkHeader(&S);
323 : 0 : cl = luaF_newLclosure(L, loadByte(&S));
324 : 0 : setclLvalue2s(L, L->top, cl);
325 : 0 : luaD_inctop(L);
326 : 0 : cl->p = luaF_newproto(L);
327 [ # # # # ]: 0 : luaC_objbarrier(L, cl, cl->p);
328 : 0 : loadFunction(&S, cl->p, NULL);
329 : : lua_assert(cl->nupvalues == cl->p->sizeupvalues);
330 : : luai_verifycode(L, cl->p);
331 : 0 : return cl;
332 : : }
333 : :
|