division safety, seperate leb functions to signed and unsigned

This commit is contained in:
Richard Holland
2022-06-02 15:09:33 +00:00
parent 6571af7490
commit 0fe9fd2f81

View File

@@ -27,8 +27,7 @@ inline uint64_t
parseLeb128( parseLeb128(
std::vector<unsigned char> const& buf, std::vector<unsigned char> const& buf,
int start_offset, int start_offset,
int* end_offset, int* end_offset)
bool is_signed = false)
{ {
uint64_t val = 0, shift = 0, i = start_offset; uint64_t val = 0, shift = 0, i = start_offset;
while (i < buf.size()) while (i < buf.size())
@@ -50,7 +49,40 @@ parseLeb128(
continue; continue;
} }
*end_offset = i; *end_offset = i;
if (is_signed && shift < 64 && (b&0x40U))
return val;
}
return 0;
}
inline int64_t
parseSignedLeb128(
std::vector<unsigned char> const& buf,
int start_offset,
int* end_offset)
{
int64_t val = 0;
uint64_t shift = 0, i = start_offset;
while (i < buf.size())
{
uint64_t b = (uint64_t)(buf[i]);
int64_t last = val;
val += (b & 0x7FU) << shift;
if (val < last)
{
// overflow
throw std::overflow_error { "leb128 overflow" };
}
++i;
if (b & 0x80U)
{
shift += 7;
if (!(i < buf.size()))
throw std::length_error { "leb128 short or invalid" };
continue;
}
*end_offset = i;
if (shift < 64 && (b&0x40U))
val |= (~0 << shift); val |= (~0 << shift);
return val; return val;
@@ -91,10 +123,10 @@ parseLeb128(
} }
#define LEB()\ #define LEB()\
parseLeb128(hook, i, &i, false) parseLeb128(hook, i, &i)
#define SIGNED_LEB()\ #define SIGNED_LEB()\
parseLeb128(hook, i, &i, true) parseSignedLeb128(hook, i, &i)
#define GUARD_ERROR(msg)\ #define GUARD_ERROR(msg)\
{\ {\
@@ -129,7 +161,8 @@ uint64_t compute_wce (const WasmBlkInf* blk)
worst_case_execution += compute_wce(&child); worst_case_execution += compute_wce(&child);
} }
if (blk->parent == 0) if (blk->parent == 0 ||
blk->parent->iteration_bound == 0) // this condtion should never occur [defensively programmed]
return worst_case_execution; return worst_case_execution;
// if the block has a parent then the quotient of its guard and its parent's guard // if the block has a parent then the quotient of its guard and its parent's guard
@@ -258,6 +291,9 @@ check_guard(
printf("iteration_bound: %d, call_func_idx: %ld, guard_func_idx: %d\n", printf("iteration_bound: %d, call_func_idx: %ld, guard_func_idx: %d\n",
iteration_bound, call_func_idx, guard_func_idx); iteration_bound, call_func_idx, guard_func_idx);
if (iteration_bound == 0)
GUARD_ERROR("Guard call cannot specify 0 maxiter.");
if (call_func_idx != guard_func_idx) if (call_func_idx != guard_func_idx)
GUARD_ERROR("Call after first and second i32.const at loop start was not _g"); GUARD_ERROR("Call after first and second i32.const at loop start was not _g");
} }
@@ -463,7 +499,7 @@ check_guard(
{ {
ADVANCE(1); ADVANCE(1);
} }
else if (fc_type >= 0 && fc_type <= 7) // numeric instructions else if (fc_type <= 7) // numeric instructions
{ {
// do nothing, these have no parameters // do nothing, these have no parameters
} }
@@ -557,7 +593,7 @@ check_guard(
REQUIRE(1); REQUIRE(1);
uint64_t v = LEB(); uint64_t v = LEB();
if (v >= 0 && v <= 11) // memargs only if (v <= 11) // memargs only
{ {
REQUIRE(1); LEB(); REQUIRE(1); LEB();
REQUIRE(1); LEB(); REQUIRE(1); LEB();