lundump.c revision 1.11
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 37typedef struct { 38 lua_State *L; 39 ZIO *Z; 40 const char *name; 41} LoadState; 42 43 44static 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 56static 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 65static 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 73static 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 87static size_t loadSize (LoadState *S) { 88 return loadUnsigned(S, ~(size_t)0); 89} 90 91 92static int loadInt (LoadState *S) { 93 return cast_int(loadUnsigned(S, INT_MAX)); 94} 95 96 97static lua_Number loadNumber (LoadState *S) { 98 lua_Number x; 99 loadVar(S, x); 100 return x; 101} 102 103 104static 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*/ 114static 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*/ 140static 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 148static 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 156static void loadFunction(LoadState *S, Proto *f, TString *psource); 157 158 159static 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 197static 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*/ 218static 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 233static 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 264static 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 281static 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 290static 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 298static 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*/ 319LClosure *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