diff options
Diffstat (limited to 'src/section/code.c')
| -rw-r--r-- | src/section/code.c | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/src/section/code.c b/src/section/code.c new file mode 100644 index 0000000..6e131e7 --- /dev/null +++ b/src/section/code.c @@ -0,0 +1,235 @@ +#include <opcodes.h> +#include <interp.h> +#include <sections.h> +#include <wasm_types.h> +#include <errno.h> +#include <inttypes.h> +#include <stdint.h> +#include <string.h> + +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; +} |
