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