lundump.c (10404B)
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 "ltable.h" 25 #include "lundump.h" 26 #include "lzio.h" 27 28 29 #if !defined(luai_verifycode) 30 #define luai_verifycode(L,f) /* empty */ 31 #endif 32 33 34 typedef struct { 35 lua_State *L; 36 ZIO *Z; 37 const char *name; 38 Table *h; /* list for string reuse */ 39 size_t offset; /* current position relative to beginning of dump */ 40 lua_Integer nstr; /* number of strings in the list */ 41 lu_byte fixed; /* dump is fixed in memory */ 42 } LoadState; 43 44 45 static l_noret error (LoadState *S, const char *why) { 46 luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why); 47 luaD_throw(S->L, LUA_ERRSYNTAX); 48 } 49 50 51 /* 52 ** All high-level loads go through loadVector; you can change it to 53 ** adapt to the endianness of the input 54 */ 55 #define loadVector(S,b,n) loadBlock(S,b,cast_sizet(n)*sizeof((b)[0])) 56 57 static void loadBlock (LoadState *S, void *b, size_t size) { 58 if (luaZ_read(S->Z, b, size) != 0) 59 error(S, "truncated chunk"); 60 S->offset += size; 61 } 62 63 64 static void loadAlign (LoadState *S, unsigned align) { 65 unsigned padding = align - cast_uint(S->offset % align); 66 if (padding < align) { /* (padding == align) means no padding */ 67 lua_Integer paddingContent; 68 loadBlock(S, &paddingContent, padding); 69 lua_assert(S->offset % align == 0); 70 } 71 } 72 73 74 #define getaddr(S,n,t) cast(t *, getaddr_(S,cast_sizet(n) * sizeof(t))) 75 76 static const void *getaddr_ (LoadState *S, size_t size) { 77 const void *block = luaZ_getaddr(S->Z, size); 78 S->offset += size; 79 if (block == NULL) 80 error(S, "truncated fixed buffer"); 81 return block; 82 } 83 84 85 #define loadVar(S,x) loadVector(S,&x,1) 86 87 88 static lu_byte loadByte (LoadState *S) { 89 int b = zgetc(S->Z); 90 if (b == EOZ) 91 error(S, "truncated chunk"); 92 S->offset++; 93 return cast_byte(b); 94 } 95 96 97 static size_t loadVarint (LoadState *S, size_t limit) { 98 size_t x = 0; 99 int b; 100 limit >>= 7; 101 do { 102 b = loadByte(S); 103 if (x > limit) 104 error(S, "integer overflow"); 105 x = (x << 7) | (b & 0x7f); 106 } while ((b & 0x80) != 0); 107 return x; 108 } 109 110 111 static size_t loadSize (LoadState *S) { 112 return loadVarint(S, MAX_SIZE); 113 } 114 115 116 static int loadInt (LoadState *S) { 117 return cast_int(loadVarint(S, cast_sizet(INT_MAX))); 118 } 119 120 121 122 static lua_Number loadNumber (LoadState *S) { 123 lua_Number x; 124 loadVar(S, x); 125 return x; 126 } 127 128 129 static lua_Integer loadInteger (LoadState *S) { 130 lua_Integer x; 131 loadVar(S, x); 132 return x; 133 } 134 135 136 /* 137 ** Load a nullable string into slot 'sl' from prototype 'p'. The 138 ** assignment to the slot and the barrier must be performed before any 139 ** possible GC activity, to anchor the string. (Both 'loadVector' and 140 ** 'luaH_setint' can call the GC.) 141 */ 142 static void loadString (LoadState *S, Proto *p, TString **sl) { 143 lua_State *L = S->L; 144 TString *ts; 145 TValue sv; 146 size_t size = loadSize(S); 147 if (size == 0) { /* no string? */ 148 lua_assert(*sl == NULL); /* must be prefilled */ 149 return; 150 } 151 else if (size == 1) { /* previously saved string? */ 152 lua_Integer idx = cast(lua_Integer, loadSize(S)); /* get its index */ 153 TValue stv; 154 luaH_getint(S->h, idx, &stv); /* get its value */ 155 *sl = ts = tsvalue(&stv); 156 luaC_objbarrier(L, p, ts); 157 return; /* do not save it again */ 158 } 159 else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */ 160 char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */ 161 loadVector(S, buff, size + 1); /* load string into buffer */ 162 *sl = ts = luaS_newlstr(L, buff, size); /* create string */ 163 luaC_objbarrier(L, p, ts); 164 } 165 else if (S->fixed) { /* for a fixed buffer, use a fixed string */ 166 const char *s = getaddr(S, size + 1, char); /* get content address */ 167 *sl = ts = luaS_newextlstr(L, s, size, NULL, NULL); 168 luaC_objbarrier(L, p, ts); 169 } 170 else { /* create internal copy */ 171 *sl = ts = luaS_createlngstrobj(L, size); /* create string */ 172 luaC_objbarrier(L, p, ts); 173 loadVector(S, getlngstr(ts), size + 1); /* load directly in final place */ 174 } 175 /* add string to list of saved strings */ 176 S->nstr++; 177 setsvalue(L, &sv, ts); 178 luaH_setint(L, S->h, S->nstr, &sv); 179 luaC_objbarrierback(L, obj2gco(S->h), ts); 180 } 181 182 183 static void loadCode (LoadState *S, Proto *f) { 184 int n = loadInt(S); 185 loadAlign(S, sizeof(f->code[0])); 186 if (S->fixed) { 187 f->code = getaddr(S, n, Instruction); 188 f->sizecode = n; 189 } 190 else { 191 f->code = luaM_newvectorchecked(S->L, n, Instruction); 192 f->sizecode = n; 193 loadVector(S, f->code, n); 194 } 195 } 196 197 198 static void loadFunction(LoadState *S, Proto *f); 199 200 201 static void loadConstants (LoadState *S, Proto *f) { 202 int i; 203 int n = loadInt(S); 204 f->k = luaM_newvectorchecked(S->L, n, TValue); 205 f->sizek = n; 206 for (i = 0; i < n; i++) 207 setnilvalue(&f->k[i]); 208 for (i = 0; i < n; i++) { 209 TValue *o = &f->k[i]; 210 int t = loadByte(S); 211 switch (t) { 212 case LUA_VNIL: 213 setnilvalue(o); 214 break; 215 case LUA_VFALSE: 216 setbfvalue(o); 217 break; 218 case LUA_VTRUE: 219 setbtvalue(o); 220 break; 221 case LUA_VNUMFLT: 222 setfltvalue(o, loadNumber(S)); 223 break; 224 case LUA_VNUMINT: 225 setivalue(o, loadInteger(S)); 226 break; 227 case LUA_VSHRSTR: 228 case LUA_VLNGSTR: { 229 lua_assert(f->source == NULL); 230 loadString(S, f, &f->source); /* use 'source' to anchor string */ 231 if (f->source == NULL) 232 error(S, "bad format for constant string"); 233 setsvalue2n(S->L, o, f->source); /* save it in the right place */ 234 f->source = NULL; 235 break; 236 } 237 default: lua_assert(0); 238 } 239 } 240 } 241 242 243 static void loadProtos (LoadState *S, Proto *f) { 244 int i; 245 int n = loadInt(S); 246 f->p = luaM_newvectorchecked(S->L, n, Proto *); 247 f->sizep = n; 248 for (i = 0; i < n; i++) 249 f->p[i] = NULL; 250 for (i = 0; i < n; i++) { 251 f->p[i] = luaF_newproto(S->L); 252 luaC_objbarrier(S->L, f, f->p[i]); 253 loadFunction(S, f->p[i]); 254 } 255 } 256 257 258 /* 259 ** Load the upvalues for a function. The names must be filled first, 260 ** because the filling of the other fields can raise read errors and 261 ** the creation of the error message can call an emergency collection; 262 ** in that case all prototypes must be consistent for the GC. 263 */ 264 static void loadUpvalues (LoadState *S, Proto *f) { 265 int i; 266 int n = loadInt(S); 267 f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); 268 f->sizeupvalues = n; 269 for (i = 0; i < n; i++) /* make array valid for GC */ 270 f->upvalues[i].name = NULL; 271 for (i = 0; i < n; i++) { /* following calls can raise errors */ 272 f->upvalues[i].instack = loadByte(S); 273 f->upvalues[i].idx = loadByte(S); 274 f->upvalues[i].kind = loadByte(S); 275 } 276 } 277 278 279 static void loadDebug (LoadState *S, Proto *f) { 280 int i; 281 int n = loadInt(S); 282 if (S->fixed) { 283 f->lineinfo = getaddr(S, n, ls_byte); 284 f->sizelineinfo = n; 285 } 286 else { 287 f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); 288 f->sizelineinfo = n; 289 loadVector(S, f->lineinfo, n); 290 } 291 n = loadInt(S); 292 if (n > 0) { 293 loadAlign(S, sizeof(int)); 294 if (S->fixed) { 295 f->abslineinfo = getaddr(S, n, AbsLineInfo); 296 f->sizeabslineinfo = n; 297 } 298 else { 299 f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); 300 f->sizeabslineinfo = n; 301 loadVector(S, f->abslineinfo, n); 302 } 303 } 304 n = loadInt(S); 305 f->locvars = luaM_newvectorchecked(S->L, n, LocVar); 306 f->sizelocvars = n; 307 for (i = 0; i < n; i++) 308 f->locvars[i].varname = NULL; 309 for (i = 0; i < n; i++) { 310 loadString(S, f, &f->locvars[i].varname); 311 f->locvars[i].startpc = loadInt(S); 312 f->locvars[i].endpc = loadInt(S); 313 } 314 n = loadInt(S); 315 if (n != 0) /* does it have debug information? */ 316 n = f->sizeupvalues; /* must be this many */ 317 for (i = 0; i < n; i++) 318 loadString(S, f, &f->upvalues[i].name); 319 } 320 321 322 static void loadFunction (LoadState *S, Proto *f) { 323 f->linedefined = loadInt(S); 324 f->lastlinedefined = loadInt(S); 325 f->numparams = loadByte(S); 326 f->flag = loadByte(S) & PF_ISVARARG; /* get only the meaningful flags */ 327 if (S->fixed) 328 f->flag |= PF_FIXED; /* signal that code is fixed */ 329 f->maxstacksize = loadByte(S); 330 loadCode(S, f); 331 loadConstants(S, f); 332 loadUpvalues(S, f); 333 loadProtos(S, f); 334 loadString(S, f, &f->source); 335 loadDebug(S, f); 336 } 337 338 339 static void checkliteral (LoadState *S, const char *s, const char *msg) { 340 char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ 341 size_t len = strlen(s); 342 loadVector(S, buff, len); 343 if (memcmp(s, buff, len) != 0) 344 error(S, msg); 345 } 346 347 348 static void fchecksize (LoadState *S, size_t size, const char *tname) { 349 if (loadByte(S) != size) 350 error(S, luaO_pushfstring(S->L, "%s size mismatch", tname)); 351 } 352 353 354 #define checksize(S,t) fchecksize(S,sizeof(t),#t) 355 356 static void checkHeader (LoadState *S) { 357 /* skip 1st char (already read and checked) */ 358 checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk"); 359 if (loadByte(S) != LUAC_VERSION) 360 error(S, "version mismatch"); 361 if (loadByte(S) != LUAC_FORMAT) 362 error(S, "format mismatch"); 363 checkliteral(S, LUAC_DATA, "corrupted chunk"); 364 checksize(S, Instruction); 365 checksize(S, lua_Integer); 366 checksize(S, lua_Number); 367 if (loadInteger(S) != LUAC_INT) 368 error(S, "integer format mismatch"); 369 if (loadNumber(S) != LUAC_NUM) 370 error(S, "float format mismatch"); 371 } 372 373 374 /* 375 ** Load precompiled chunk. 376 */ 377 LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) { 378 LoadState S; 379 LClosure *cl; 380 if (*name == '@' || *name == '=') 381 S.name = name + 1; 382 else if (*name == LUA_SIGNATURE[0]) 383 S.name = "binary string"; 384 else 385 S.name = name; 386 S.L = L; 387 S.Z = Z; 388 S.fixed = cast_byte(fixed); 389 S.offset = 1; /* fist byte was already read */ 390 checkHeader(&S); 391 cl = luaF_newLclosure(L, loadByte(&S)); 392 setclLvalue2s(L, L->top.p, cl); 393 luaD_inctop(L); 394 S.h = luaH_new(L); /* create list of saved strings */ 395 S.nstr = 0; 396 sethvalue2s(L, L->top.p, S.h); /* anchor it */ 397 luaD_inctop(L); 398 cl->p = luaF_newproto(L); 399 luaC_objbarrier(L, cl, cl->p); 400 loadFunction(&S, cl->p); 401 lua_assert(cl->nupvalues == cl->p->sizeupvalues); 402 luai_verifycode(L, cl->p); 403 L->top.p--; /* pop table */ 404 return cl; 405 } 406