diff --git a/src/Makefile b/src/Makefile index 7e006c512acd4f8f868067445f6f07de17996133..670a4daf102f28bba74c9254ab64ffbea072ba57 100644 --- a/src/Makefile +++ b/src/Makefile @@ -14,7 +14,7 @@ all: libhammer.a test_suite test_suite: test_suite.o libhammer.a $(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS) -libhammer.a: bitreader.o hammer.o +libhammer.a: bitreader.o hammer.o pprint.o bitreader.o: test_suite.h -hammer.o: hammer.h \ No newline at end of file +hammer.o: hammer.h diff --git a/src/bitreader.c b/src/bitreader.c index 0b406e01e9a4843a5999fee17f1decaecda6cb4e..d3553f0155d6d8db250f4839a4894e5a3b4670c9 100644 --- a/src/bitreader.c +++ b/src/bitreader.c @@ -13,14 +13,37 @@ long long read_bits(input_stream_t* state, int count, char signed_p) { // BUG: Does not long long out = 0; int offset = 0; + int final_shift = 0; 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) { // fast path if (state->endianness & BYTE_BIG_ENDIAN) { - while (count > 0) + while (count > 0) { + count -= 8; out = (out << 8) | state->input[state->index++]; + } } else { while (count > 0) { count -= 8; @@ -65,6 +88,7 @@ long long read_bits(input_stream_t* state, int count, char signed_p) { count -= segment_len; } } + out <<= final_shift; return (out ^ msb) - msb; // perform sign extension } diff --git a/src/hammer.c b/src/hammer.c index 0eefcee8f6b509b9f8d19ab5c07a64f2d95dc851..e6f984cd1e04211ca6ec389620a52296c5bb0c99 100644 --- a/src/hammer.c +++ b/src/hammer.c @@ -72,6 +72,8 @@ parse_result_t* do_parse(const parser_t* parser, parse_state_t *state) { // It doesn't exist... run the parse_result_t *res; res = parser->fn(parser->env, state); + if (state->input_stream.overrun) + res = NULL; // overrun is always failure. // update the cache g_hash_table_replace(state->cache, &key, res); #ifdef CONSISTENCY_CHECK @@ -166,7 +168,7 @@ const parser_t* range(const uint8_t lower, const uint8_t upper) { return (const parser_t*)ret; } -const parser_t* notin(const uint8_t *options, int count) { +const parser_t* not_in(const uint8_t *options, int count) { parser_t *ret = g_new(parser_t, 1); charset cs = new_charset(); for (int i = 0; i < 256; i++) @@ -604,11 +606,11 @@ static void test_left_factor_action(void) { } -static void test_notin(void) { +static void test_not_in(void) { uint8_t options[3] = { 'a', 'b', 'c' }; uint8_t test1[1] = { 'd' }; uint8_t test2[1] = { 'a' }; - const parser_t *notin_ = notin(options, 3); + const parser_t *not_in_ = not_in(options, 3); parse_result_t *ret1 = parse(notin_, test1, 1); parse_result_t *ret2 = parse(notin_, test2, 1); g_check_cmpint(ret1->ast->uint, ==, 'd'); @@ -738,7 +740,7 @@ void register_parser_tests(void) { g_test_add_func("/core/parser/whitespace", test_whitespace); g_test_add_func("/core/parser/action", test_action); g_test_add_func("/core/parser/left_factor_action", test_left_factor_action); - g_test_add_func("/core/parser/notin", test_notin); + g_test_add_func("/core/parser/not_in", test_not_in); g_test_add_func("/core/parser/end_p", test_end_p); g_test_add_func("/core/parser/nothing_p", test_nothing_p); g_test_add_func("/core/parser/sequence", test_sequence); diff --git a/src/hammer.h b/src/hammer.h index 19eced8c187443b57990e9aa3a8358f902bcefa6..1b84861e432640f86d1d6bf8c277e20838840a1e 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -42,6 +42,7 @@ typedef struct input_stream { size_t length; char bit_offset; char endianness; + char overrun; } input_stream_t; typedef struct parse_state { @@ -138,7 +139,7 @@ const parser_t* whitespace(const parser_t* p); const parser_t* left_factor_action(const parser_t* p); /* Parse a single character *NOT* in charset */ -const parser_t* notin(const uint8_t *options, int count); +const parser_t* not_in(const uint8_t *charset, int length); /* A no-argument parser that succeeds if there is no more input to parse. */ const parser_t* end_p();