/* * 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 #include static int dump_import_name(FILE *const f, const varuint32 len) { for (varuint32 i = 0; i < len; i++) { uint8_t byte; if (!fread(&byte, sizeof byte, 1, f)) { LOG("%s: fread(3) failed, feof=%d, ferror=%d\n", __func__, feof(f), ferror(f)); return -1; } LOG("%c", (char)byte); } return 0; } static int check_module_string(const struct nw_mod_cfg *const cfg, FILE *const f) { varuint32 len; if (varuint32_read(f, &len)) { LOG("%s: varuint32_read failed\n", __func__); return -1; } for (size_t i = 0; i < cfg->n_imports; i++) { const struct nw_import *const im = &cfg->imports[i]; const char *const mod = im->module; if (strlen(mod) == len) { const long offset = ftell(f); if (offset < 0) { LOG("%s: ftell(3): %s\n", __func__, strerror(errno)); return -1; } else if (!fstrcmp(mod, f, true)) return 0; else if (fseek(f, offset, SEEK_SET)) { LOG("%s: fseek(3): %s\n", __func__, strerror(errno)); return -1; } } } LOG("%s: required imported module ", __func__); dump_import_name(f, len); LOG(" not found\n"); return -1; } static int check_field_string(const struct nw_mod_cfg *const cfg, FILE *const f) { varuint32 len; if (varuint32_read(f, &len)) { LOG("%s: varuint32_read failed\n", __func__); return -1; } for (size_t i = 0; i < cfg->n_imports; i++) { const struct nw_import *const im = &cfg->imports[i]; const char *const field = im->field; if (strlen(field) == len) { const long offset = ftell(f); if (offset < 0) { LOG("%s: ftell(3): %s\n", __func__, strerror(errno)); return -1; } else if (!fstrcmp(field, f, true)) return 0; else if (fseek(f, offset, SEEK_SET)) { LOG("%s: fseek(3): %s\n", __func__, strerror(errno)); return -1; } } } LOG("%s: required imported field ", __func__); dump_import_name(f, len); LOG(" not found\n"); return -1; } static int check_function_kind(FILE *const f) { varuint32 type; if (varuint32_read(f, &type)) { LOG("%s: varuint32_read failed\n", __func__); return -1; } return 0; } static int check_table_kind(FILE *const f) { varint7 type; if (varint7_read(f, &type)) { LOG("%s: varint7_read failed\n", __func__); return -1; } return 0; } static int check_memory_kind(FILE *const f) { /* TODO. */ return -1; } static int check_global_kind(FILE *const f) { /* TODO. */ return -1; } static int check_import_entry(const struct nw_mod_cfg *const cfg, FILE *const f) { if (check_module_string(cfg, f)) { LOG("%s: check_module_string failed\n", __func__); return -1; } else if (check_field_string(cfg, f)) { LOG("%s: check_field_string failed\n", __func__); return -1; } uint8_t kind; if (!fread(&kind, sizeof kind, 1, f)) { LOG("%s: fread(3) failed, feof=%d, ferror=%d\n", __func__, feof(f), ferror(f)); return -1; } static int (*const fn[])(FILE *) = { [NW_KIND_FUNCTION] = check_function_kind, [NW_KIND_TABLE] = check_table_kind, [NW_KIND_MEMORY] = check_memory_kind, [NW_KIND_GLOBAL] = check_global_kind }; if (kind >= sizeof fn / sizeof *fn) { LOG("%s: unexpected kind %#" PRIx8 "\n", __func__, kind); return -1; } return fn[kind](f); } static int check(const struct nw_mod_cfg *const cfg, FILE *const f, const unsigned long len) { const long start = ftell(f); if (start < 0) { LOG("%s: ftell(3): %s\n", __func__, strerror(errno)); return -1; } varuint32 count; if (varuint32_read(f, &count)) { LOG("%s: varuint32_read failed\n", __func__); return -1; } for (varuint32 i = 0; i < count; i++) if (check_import_entry(cfg, f)) { LOG("%s: check_import_entry failed\n", __func__); return -1; } const long end = ftell(f); if (end < 0) { LOG("%s: ftell(3): %s\n", __func__, strerror(errno)); return -1; } const unsigned long size = end - start; if (size != len) { LOG("%s: size exceeded (%lu expected, got %lu)\n", __func__, len, size); return -1; } return 0; } int section_import_check(const struct section *const s, struct nw_mod *m, const unsigned long len) { const struct nw_mod_cfg *const cfg = s->cfg; FILE *const f = s->f; if (m->sections.import) { LOG("%s: ignoring duplicate section\n", __func__); return fseek(f, len, SEEK_CUR); } const long offset = ftell(f); if (offset < 0) { LOG("%s: ftell(3): %s\n", __func__, strerror(errno)); return -1; } else if (check(cfg, f, len)) { LOG("%s: check failed\n", __func__); return -1; } m->sections.import = offset; return 0; }