239 lines
4.8 KiB
C
239 lines
4.8 KiB
C
#include <log.h>
|
|
#include <nanowasm/nw.h>
|
|
#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)
|
|
{
|
|
LOG("%s: ftell(3) before: %s\n", __func__,
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
else if (!fread(&byte, sizeof byte, 1, f))
|
|
{
|
|
LOG("%s: fread(3) failed, feof=%d, ferror=%d\n",
|
|
__func__, feof(f), ferror(f));
|
|
return -1;
|
|
}
|
|
else if (rem == 1 && byte != OP_END)
|
|
{
|
|
LOG("%s: unexpected opcode %#" PRIx8 " at body end\n",
|
|
__func__, byte);
|
|
return -1;
|
|
}
|
|
else if (interp_check_opcode(byte, f))
|
|
{
|
|
LOG("%s: interp_check_opcode failed\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
const long after = ftell(f);
|
|
|
|
if (after < 0)
|
|
{
|
|
LOG("%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))
|
|
{
|
|
LOG("%s: varint7_read failed\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_local(FILE *const f)
|
|
{
|
|
varuint32 count;
|
|
|
|
if (varuint32_read(f, &count))
|
|
{
|
|
LOG("%s: varuint32_read failed\n", __func__);
|
|
return -1;
|
|
}
|
|
else if (check_type(f))
|
|
{
|
|
LOG("%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))
|
|
{
|
|
LOG("%s: varuint32_read local_count failed\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
for (varuint32 i = 0; i < local_count; i++)
|
|
if (check_local(f))
|
|
{
|
|
LOG("%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))
|
|
{
|
|
LOG("%s: varuint32_read body_size failed\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
const long start = ftell(f);
|
|
|
|
if (start < 0)
|
|
{
|
|
LOG("%s: ftell(3) start: %s\n", __func__, strerror(errno));
|
|
return -1;
|
|
}
|
|
else if (check_locals(f))
|
|
{
|
|
LOG("%s: check_locals failed\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
const long end = ftell(f);
|
|
|
|
if (end < 0)
|
|
{
|
|
LOG("%s: ftell(3) end: %s\n", __func__, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
const unsigned long consumed = end - start;
|
|
|
|
if (consumed > body_size)
|
|
{
|
|
LOG("%s: exceeded function body size\n", __func__);
|
|
return -1;
|
|
}
|
|
else if (check_body(f, body_size - consumed))
|
|
{
|
|
LOG("%s: check_body failed\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
/* TODO: add function body pointers to struct nanowasm. */
|
|
return 0;
|
|
}
|
|
|
|
static int check_function_bodies(FILE *const f)
|
|
{
|
|
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_function_body(f))
|
|
{
|
|
LOG("%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)
|
|
{
|
|
LOG("%s: ftell(3): %s\n", __func__, strerror(errno));
|
|
return -1;
|
|
}
|
|
else if (check_function_bodies(f))
|
|
{
|
|
LOG("%s: check_function_bodies 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_code(const struct nw_mod_cfg *const cfg,
|
|
struct nw_mod *const m, FILE *const f, const unsigned long len)
|
|
{
|
|
if (m->sections.code)
|
|
{
|
|
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(f, len))
|
|
{
|
|
LOG("%s: check failed\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
m->sections.code = offset;
|
|
return 0;
|
|
}
|