/* * nanowasm, a tiny WebAssembly/Wasm interpreter * Copyright (C) 2023-2024 Xavier Del Campo Romero * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include static int check_magic(FILE *const f) { static const uint8_t m[] = {'\0', 'a', 's', 'm'}; uint8_t magic[sizeof m]; if (!fread(magic, sizeof magic, 1, f)) { LOG("%s: fread(3) failed, feof=%d, ferror=%d\n", __func__, feof(f), ferror(f)); return -1; } else if (memcmp(magic, m, sizeof magic)) { LOG("%s: wrong magic bytes\n", __func__); return -1; } return 0; } static int check_version(FILE *const f) { static const uint8_t v[] = {1, 0, 0, 0}; uint8_t version[sizeof v]; if (!fread(version, sizeof version, 1, f)) { LOG("%s: fread(3) failed, feof=%d, ferror=%d\n", __func__, feof(f), ferror(f)); return -1; } else if (memcmp(version, v, sizeof version)) { LOG("%s: wrong version\n", __func__); return -1; } return 0; } static int load_section(const struct nw_mod_cfg *const cfg, struct nw_mod *const m, FILE *const f) { static int (*const fn[])(const struct section *, struct nw_mod *, unsigned long) = { section_custom_check, section_type_check, section_import_check, section_function_check, section_table_check, section_memory_check, section_global_check, section_export_check, section_start_check, section_element_check, section_code_check, section_data_check }; const struct section s = { .cfg = cfg, .f = f }; varuint7 section; varuint32 len; int ret; if (varuint7_read(f, §ion)) { if (feof(f)) return 0; LOG("%s: varuint7_read failed\n", __func__); return 1; } else if (section >= sizeof fn / sizeof *fn) { LOG("%s: invalid section %u\n", __func__, (unsigned)section); return 1; } else if (varuint32_read(f, &len)) { LOG("%s: varuint32_read failed\n", __func__); return 1; } else if ((ret = fn[section](&s, m, len))) LOG("%s: failed to load section %u\n", __func__, (unsigned)section); return ret; } static int load_sections(const struct nw_mod_cfg *const cfg, struct nw_mod *const m, FILE *const f) { while (!feof(f)) if (load_section(cfg, m, f)) { LOG("%s: load_section failed\n", __func__); return -1; } return 0; } static int load(const struct nw_mod_cfg *const cfg, struct nw_mod *const m, FILE *const f) { if (check_magic(f)) { LOG("%s: load_magic failed\n", __func__); return -1; } else if (check_version(f)) { LOG("%s: check_version failed\n", __func__); return -1; } else if (load_sections(cfg, m, f)) { LOG("%s: load_sections failed\n", __func__); return -1; } return 0; } int nw_load(const struct nw_mod_cfg *const cfg, struct nw_mod *const m) { int ret = -1; FILE *const f = fopen(cfg->path, "rb"); *m = (const struct nw_mod){.cfg = *cfg}; if (!f) { LOG("%s: fopen(3) %s: %s\n", __func__, cfg->path, strerror(errno)); goto end; } else if (load(cfg, m, f)) { LOG("%s: load failed\n", __func__); goto end; } ret = 0; end: if (f && fclose(f)) { LOG("%s: fclose(3) %s: %s\n", __func__, cfg->path, strerror(errno)); ret = -1; } return ret; }