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 (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 | |