Added overrun protection
This commit is contained in:
parent
d6c0eaf3de
commit
dc0a7572f7
3 changed files with 29 additions and 2 deletions
|
|
@ -13,14 +13,37 @@ long long read_bits(input_stream_t* state, int count, char signed_p) {
|
||||||
// BUG: Does not
|
// BUG: Does not
|
||||||
long long out = 0;
|
long long out = 0;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
int final_shift = 0;
|
||||||
long long msb = (!!signed_p) << (count - 1); // 0 if unsigned, else 1 << (nbits - 1)
|
long long msb = (!!signed_p) << (count - 1); // 0 if unsigned, else 1 << (nbits - 1)
|
||||||
// BUG: does not stop early in case of
|
|
||||||
|
|
||||||
|
// overflow check...
|
||||||
|
int bits_left = (state->length - state->index); // well, bytes for now
|
||||||
|
if (bits_left <= 64) { // Large enough to handle any valid count, but small enough that overflow isn't a problem.
|
||||||
|
// not in danger of overflowing, so add in bits
|
||||||
|
// add in number of bits...
|
||||||
|
if (state->endianness & BIT_BIG_ENDIAN)
|
||||||
|
bits_left = (bits_left << 3) - 8 + state->bit_offset;
|
||||||
|
else
|
||||||
|
bits_left = (bits_left << 3) - state->bit_offset;
|
||||||
|
if (bits_left < count) {
|
||||||
|
if (state->endianness & BYTE_BIG_ENDIAN)
|
||||||
|
final_shift = count - bits_left;
|
||||||
|
else
|
||||||
|
final_shift = 0;
|
||||||
|
count = bits_left;
|
||||||
|
state->overrun = true;
|
||||||
|
} else
|
||||||
|
final_shift = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((state->bit_offset & 0x7) == 0 && (count & 0x7) == 0) {
|
if ((state->bit_offset & 0x7) == 0 && (count & 0x7) == 0) {
|
||||||
// fast path
|
// fast path
|
||||||
if (state->endianness & BYTE_BIG_ENDIAN) {
|
if (state->endianness & BYTE_BIG_ENDIAN) {
|
||||||
while (count > 0)
|
while (count > 0) {
|
||||||
|
count -= 8;
|
||||||
out = (out << 8) | state->input[state->index++];
|
out = (out << 8) | state->input[state->index++];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
count -= 8;
|
count -= 8;
|
||||||
|
|
@ -65,6 +88,7 @@ long long read_bits(input_stream_t* state, int count, char signed_p) {
|
||||||
count -= segment_len;
|
count -= segment_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out <<= final_shift;
|
||||||
return (out ^ msb) - msb; // perform sign extension
|
return (out ^ msb) - msb; // perform sign extension
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ parse_result_t* do_parse(const parser_t* parser, parse_state_t *state) {
|
||||||
// It doesn't exist... run the
|
// It doesn't exist... run the
|
||||||
parse_result_t *res;
|
parse_result_t *res;
|
||||||
res = parser->fn(parser->env, state);
|
res = parser->fn(parser->env, state);
|
||||||
|
if (state->input.overrun)
|
||||||
|
res = NULL; // overrun is always failure.
|
||||||
// update the cache
|
// update the cache
|
||||||
g_hash_table_replace(state->cache, &key, res);
|
g_hash_table_replace(state->cache, &key, res);
|
||||||
#ifdef CONSISTENCY_CHECK
|
#ifdef CONSISTENCY_CHECK
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ typedef struct input_stream {
|
||||||
size_t length;
|
size_t length;
|
||||||
char bit_offset;
|
char bit_offset;
|
||||||
char endianness;
|
char endianness;
|
||||||
|
char overrun;
|
||||||
} input_stream_t;
|
} input_stream_t;
|
||||||
|
|
||||||
typedef struct parse_state {
|
typedef struct parse_state {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue