1 /*
2 ** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 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 
error(LoadState * S,const char * why)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 
LoadBlock(LoadState * S,void * b,size_t size)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 
LoadByte(LoadState * S)60 static lu_byte LoadByte (LoadState *S) {
61   lu_byte x;
62   LoadVar(S, x);
63   return x;
64 }
65 
66 
LoadInt(LoadState * S)67 static int LoadInt (LoadState *S) {
68   int x;
69   LoadVar(S, x);
70   return x;
71 }
72 
73 
LoadNumber(LoadState * S)74 static lua_Number LoadNumber (LoadState *S) {
75   lua_Number x;
76   LoadVar(S, x);
77   return x;
78 }
79 
80 
LoadInteger(LoadState * S)81 static lua_Integer LoadInteger (LoadState *S) {
82   lua_Integer x;
83   LoadVar(S, x);
84   return x;
85 }
86 
87 
LoadString(LoadState * S)88 static TString *LoadString (LoadState *S) {
89   size_t size = LoadByte(S);
90   if (size == 0xFF)
91     LoadVar(S, size);
92   if (size == 0)
93     return NULL;
94   else if (--size <= LUAI_MAXSHORTLEN) {  /* short string? */
95     char buff[LUAI_MAXSHORTLEN];
96     LoadVector(S, buff, size);
97     return luaS_newlstr(S->L, buff, size);
98   }
99   else {  /* long string */
100     TString *ts = luaS_createlngstrobj(S->L, size);
101     LoadVector(S, getstr(ts), size);  /* load directly in final place */
102     return ts;
103   }
104 }
105 
106 
LoadCode(LoadState * S,Proto * f)107 static void LoadCode (LoadState *S, Proto *f) {
108   int n = LoadInt(S);
109   f->code = luaM_newvector(S->L, n, Instruction);
110   f->sizecode = n;
111   LoadVector(S, f->code, n);
112 }
113 
114 
115 static void LoadFunction(LoadState *S, Proto *f, TString *psource);
116 
117 
LoadConstants(LoadState * S,Proto * f)118 static void LoadConstants (LoadState *S, Proto *f) {
119   int i;
120   int n = LoadInt(S);
121   f->k = luaM_newvector(S->L, n, TValue);
122   f->sizek = n;
123   for (i = 0; i < n; i++)
124     setnilvalue(&f->k[i]);
125   for (i = 0; i < n; i++) {
126     TValue *o = &f->k[i];
127     int t = LoadByte(S);
128     switch (t) {
129     case LUA_TNIL:
130       setnilvalue(o);
131       break;
132     case LUA_TBOOLEAN:
133       setbvalue(o, LoadByte(S));
134       break;
135     case LUA_TNUMFLT:
136       setfltvalue(o, LoadNumber(S));
137       break;
138     case LUA_TNUMINT:
139       setivalue(o, LoadInteger(S));
140       break;
141     case LUA_TSHRSTR:
142     case LUA_TLNGSTR:
143       setsvalue2n(S->L, o, LoadString(S));
144       break;
145     default:
146       lua_assert(0);
147     }
148   }
149 }
150 
151 
LoadProtos(LoadState * S,Proto * f)152 static void LoadProtos (LoadState *S, Proto *f) {
153   int i;
154   int n = LoadInt(S);
155   f->p = luaM_newvector(S->L, n, Proto *);
156   f->sizep = n;
157   for (i = 0; i < n; i++)
158     f->p[i] = NULL;
159   for (i = 0; i < n; i++) {
160     f->p[i] = luaF_newproto(S->L);
161     LoadFunction(S, f->p[i], f->source);
162   }
163 }
164 
165 
LoadUpvalues(LoadState * S,Proto * f)166 static void LoadUpvalues (LoadState *S, Proto *f) {
167   int i, n;
168   n = LoadInt(S);
169   f->upvalues = luaM_newvector(S->L, n, Upvaldesc);
170   f->sizeupvalues = n;
171   for (i = 0; i < n; i++)
172     f->upvalues[i].name = NULL;
173   for (i = 0; i < n; i++) {
174     f->upvalues[i].instack = LoadByte(S);
175     f->upvalues[i].idx = LoadByte(S);
176   }
177 }
178 
179 
LoadDebug(LoadState * S,Proto * f)180 static void LoadDebug (LoadState *S, Proto *f) {
181   int i, n;
182   n = LoadInt(S);
183   f->lineinfo = luaM_newvector(S->L, n, int);
184   f->sizelineinfo = n;
185   LoadVector(S, f->lineinfo, n);
186   n = LoadInt(S);
187   f->locvars = luaM_newvector(S->L, n, LocVar);
188   f->sizelocvars = n;
189   for (i = 0; i < n; i++)
190     f->locvars[i].varname = NULL;
191   for (i = 0; i < n; i++) {
192     f->locvars[i].varname = LoadString(S);
193     f->locvars[i].startpc = LoadInt(S);
194     f->locvars[i].endpc = LoadInt(S);
195   }
196   n = LoadInt(S);
197   for (i = 0; i < n; i++)
198     f->upvalues[i].name = LoadString(S);
199 }
200 
201 
LoadFunction(LoadState * S,Proto * f,TString * psource)202 static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
203   f->source = LoadString(S);
204   if (f->source == NULL)  /* no source in dump? */
205     f->source = psource;  /* reuse parent's source */
206   f->linedefined = LoadInt(S);
207   f->lastlinedefined = LoadInt(S);
208   f->numparams = LoadByte(S);
209   f->is_vararg = LoadByte(S);
210   f->maxstacksize = LoadByte(S);
211   LoadCode(S, f);
212   LoadConstants(S, f);
213   LoadUpvalues(S, f);
214   LoadProtos(S, f);
215   LoadDebug(S, f);
216 }
217 
218 
checkliteral(LoadState * S,const char * s,const char * msg)219 static void checkliteral (LoadState *S, const char *s, const char *msg) {
220   char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
221   size_t len = strlen(s);
222   LoadVector(S, buff, len);
223   if (memcmp(s, buff, len) != 0)
224     error(S, msg);
225 }
226 
227 
fchecksize(LoadState * S,size_t size,const char * tname)228 static void fchecksize (LoadState *S, size_t size, const char *tname) {
229   if (LoadByte(S) != size)
230     error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname));
231 }
232 
233 
234 #define checksize(S,t)	fchecksize(S,sizeof(t),#t)
235 
checkHeader(LoadState * S)236 static void checkHeader (LoadState *S) {
237   checkliteral(S, LUA_SIGNATURE + 1, "not a");  /* 1st char already checked */
238   if (LoadByte(S) != LUAC_VERSION)
239     error(S, "version mismatch in");
240   if (LoadByte(S) != LUAC_FORMAT)
241     error(S, "format mismatch in");
242   checkliteral(S, LUAC_DATA, "corrupted");
243   checksize(S, int);
244   checksize(S, size_t);
245   checksize(S, Instruction);
246   checksize(S, lua_Integer);
247   checksize(S, lua_Number);
248   if (LoadInteger(S) != LUAC_INT)
249     error(S, "endianness mismatch in");
250   if (LoadNumber(S) != LUAC_NUM)
251     error(S, "float format mismatch in");
252 }
253 
254 
255 /*
256 ** load precompiled chunk
257 */
luaU_undump(lua_State * L,ZIO * Z,const char * name)258 LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
259   LoadState S;
260   LClosure *cl;
261   if (*name == '@' || *name == '=')
262     S.name = name + 1;
263   else if (*name == LUA_SIGNATURE[0])
264     S.name = "binary string";
265   else
266     S.name = name;
267   S.L = L;
268   S.Z = Z;
269   checkHeader(&S);
270   cl = luaF_newLclosure(L, LoadByte(&S));
271   setclLvalue(L, L->top, cl);
272   luaD_inctop(L);
273   cl->p = luaF_newproto(L);
274   LoadFunction(&S, cl->p, NULL);
275   lua_assert(cl->nupvalues == cl->p->sizeupvalues);
276   luai_verifycode(L, buff, cl->p);
277   return cl;
278 }
279 
280