diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index a660be99..556b30f6 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -64,7 +64,111 @@ void smlua_exec_str(char* str) { lua_pop(L, lua_gettop(L)); } +#define LUA_BOM_11 0x0000000000005678llu +#define LUA_BOM_19 0x4077280000000000llu + +static bool smlua_check_binary_header(struct ModFile *file) { + FILE *f = fopen(file->cachedPath, "rb"); + if (f) { + + // Read signature + char signature[sizeof(LUA_SIGNATURE)] = {0}; + if (fread(signature, 1, sizeof(LUA_SIGNATURE) - 1, f) != sizeof(LUA_SIGNATURE) - 1) { + LOG_LUA("Failed to load lua script '%s': File too short.", file->cachedPath); + fclose(f); + return false; + } + + // Check signature + if (strcmp(signature, LUA_SIGNATURE) != 0) { + fclose(f); + return true; // Not a binary lua + } + + // Read version number + u8 version; + if (fread(&version, 1, 1, f) != 1) { + LOG_LUA("Failed to load lua script '%s': File too short.", file->cachedPath); + fclose(f); + return false; + } + + // Check version number + u8 expectedVersion = strtoul(LUA_VERSION_MAJOR LUA_VERSION_MINOR, NULL, 16); + if (version != expectedVersion) { + LOG_LUA("Failed to load lua script '%s': Lua versions don't match (%X, expected %X).", file->cachedPath, version, expectedVersion); + fclose(f); + return false; + } + + // Read the rest of the header + u8 header[28]; + if (fread(header, 1, 28, f) != 28) { + LOG_LUA("Failed to load lua script '%s': File too short.", file->cachedPath); + fclose(f); + return false; + } + + // The following errors are silent (they're due to non-matching endianness/bitness and shouldn't prevent the rest of the mod from loading) + + // Check endianness + u64 bom11 = *((u64 *) (header + 12)); + u64 bom19 = *((u64 *) (header + 20)); + if (bom11 != LUA_BOM_11) { + LOG_ERROR("Failed to load lua script '%s': BOM at offset 0x11 don't match (%016llX, expected %016llX).", file->cachedPath, bom11, LUA_BOM_11); + fclose(f); + return false; + } + if (bom19 != LUA_BOM_19) { + LOG_ERROR("Failed to load lua script '%s': BOM at offset 0x19 don't match (%016llX, expected %016llX).", file->cachedPath, bom19, LUA_BOM_19); + fclose(f); + return false; + } + + // Check sizes + u8 sizeOfCInteger = header[7]; + u8 sizeOfCPointer = header[8]; + u8 sizeOfCFloat = header[9]; + u8 sizeOfLuaInteger = header[10]; + u8 sizeOfLuaNumber = header[11]; + if (sizeOfCInteger != sizeof(int)) { + LOG_ERROR("Failed to load lua script '%s': sizes of C Integer don't match (%d, expected %llu).", file->cachedPath, sizeOfCInteger, sizeof(int)); + fclose(f); + return false; + } + if (sizeOfCPointer != sizeof(void *)) { // 4 for 32-bit architectures, 8 for 64-bit + LOG_ERROR("Failed to load lua script '%s': sizes of C Pointer don't match (%d, expected %llu).", file->cachedPath, sizeOfCPointer, sizeof(void *)); + fclose(f); + return false; + } + if (sizeOfCFloat != sizeof(float)) { + LOG_ERROR("Failed to load lua script '%s': sizes of C Float don't match (%d, expected %llu).", file->cachedPath, sizeOfCFloat, sizeof(float)); + fclose(f); + return false; + } + if (sizeOfLuaInteger != sizeof(LUA_INTEGER)) { + LOG_ERROR("Failed to load lua script '%s': sizes of Lua Integer don't match (%d, expected %llu).", file->cachedPath, sizeOfLuaInteger, sizeof(LUA_INTEGER)); + fclose(f); + return false; + } + if (sizeOfLuaNumber != sizeof(LUA_NUMBER)) { + LOG_ERROR("Failed to load lua script '%s': sizes of Lua Number don't match (%d, expected %llu).", file->cachedPath, sizeOfLuaNumber, sizeof(LUA_NUMBER)); + fclose(f); + return false; + } + + // All's good + LOG_INFO("Loading lua script '%s'", file->cachedPath); + fclose(f); + return true; + } + LOG_LUA("Failed to load lua script '%s': File not found.", file->cachedPath); + return false; +} + static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteIndex) { + if (!smlua_check_binary_header(file)) return; + lua_State* L = gLuaState; lua_settop(L, 0);