#include #include #include #include #include #include #include #include static int check_body(FILE *const f, const unsigned long n) { unsigned long rem = n; while (rem) { const long before = ftell(f); uint8_t byte; if (before < 0) { fprintf(stderr, "%s: ftell(3) before: %s\n", __func__, strerror(errno)); return -1; } else if (!fread(&byte, sizeof byte, 1, f)) { fprintf(stderr, "%s: fread(3) failed, feof=%d, ferror=%d\n", __func__, feof(f), ferror(f)); return -1; } else if (rem == 1 && byte != OP_END) { fprintf(stderr, "%s: unexpected opcode %#" PRIx8 " at body end\n", __func__, byte); return -1; } else if (interp_check_opcode(byte, f)) { fprintf(stderr, "%s: interp_check_opcode failed\n", __func__); return -1; } const long after = ftell(f); if (after < 0) { fprintf(stderr, "%s: ftell(3) after: %s\n", __func__, strerror(errno)); return -1; } rem -= after - before; } return 0; } static int check_type(FILE *const f) { varint7 type; if (varint7_read(f, &type)) { fprintf(stderr, "%s: varint7_read failed\n", __func__); return -1; } return 0; } static int check_local(FILE *const f) { varuint32 count; if (varuint32_read(f, &count)) { fprintf(stderr, "%s: varuint32_read failed\n", __func__); return -1; } else if (check_type(f)) { fprintf(stderr, "%s: check_type failed\n", __func__); return -1; } return 0; } static int check_locals(FILE *const f) { varuint32 local_count; if (varuint32_read(f, &local_count)) { fprintf(stderr, "%s: varuint32_read local_count failed\n", __func__); return -1; } for (varuint32 i = 0; i < local_count; i++) if (check_local(f)) { fprintf(stderr, "%s: check_local failed\n", __func__); return -1; } return 0; } static int check_function_body(FILE *const f) { varuint32 body_size; if (varuint32_read(f, &body_size)) { fprintf(stderr, "%s: varuint32_read body_size failed\n", __func__); return -1; } const long start = ftell(f); if (start < 0) { fprintf(stderr, "%s: ftell(3) start: %s\n", __func__, strerror(errno)); return -1; } else if (check_locals(f)) { fprintf(stderr, "%s: check_locals failed\n", __func__); return -1; } const long end = ftell(f); if (end < 0) { fprintf(stderr, "%s: ftell(3) end: %s\n", __func__, strerror(errno)); return -1; } const unsigned long consumed = end - start; if (consumed > body_size) { fprintf(stderr, "%s: exceeded function body size\n", __func__); return -1; } else if (check_body(f, body_size - consumed)) { fprintf(stderr, "%s: check_body failed\n", __func__); return -1; } return 0; } static int check_function_bodies(FILE *const f) { varuint32 count; if (varuint32_read(f, &count)) { fprintf(stderr, "%s: varuint32_read failed\n", __func__); return -1; } for (varuint32 i = 0; i < count; i++) if (check_function_body(f)) { fprintf(stderr, "%s: check_function_body failed\n", __func__); return -1; } return 0; } static int check(FILE *const f, const unsigned long len) { const long start = ftell(f); if (start < 0) { fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno)); return -1; } else if (check_function_bodies(f)) { fprintf(stderr, "%s: check_function_bodies failed\n", __func__); return -1; } const long end = ftell(f); if (end < 0) { fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno)); return -1; } const unsigned long size = end - start; if (size != len) { fprintf(stderr, "%s: size exceeded (%lu expected, got %lu)\n", __func__, len, size); return -1; } return 0; } int section_code(struct wasmfs *const w, FILE *const f, const unsigned long len) { if (w->sections.code) { fprintf(stderr, "%s: ignoring duplicate section\n", __func__); return 0; } const long offset = ftell(f); if (offset < 0) { fprintf(stderr, "%s: ftell(3): %s\n", __func__, strerror(errno)); return -1; } else if (check(f, len)) { fprintf(stderr, "%s: check failed\n", __func__); return -1; } w->sections.code = offset; return 0; }