diff --git a/src/fstapi.c b/src/fstapi.c index 5bd4331..1afb149 100644 --- a/src/fstapi.c +++ b/src/fstapi.c @@ -617,26 +617,27 @@ static int fstWriterVarint(FILE *handle, uint64_t v) static int64_t fstGetSVarint64(unsigned char *mem, int *skiplen) { unsigned char *mem_orig = mem; - int64_t rc = 0; - const int64_t one = 1; + uint64_t rc = 0; const int siz = sizeof(int64_t) * 8; int shift = 0; unsigned char byt; do { byt = *(mem++); - rc |= ((int64_t)(byt & 0x7f)) << shift; + if (shift < siz) { + rc |= ((uint64_t)(byt & 0x7f)) << shift; + } shift += 7; } while (byt & 0x80); if ((shift < siz) && (byt & 0x40)) { - rc |= -(one << shift); /* sign extend */ + rc |= ~(uint64_t)0 << shift; /* sign extend */ } *skiplen = mem - mem_orig; - return (rc); + return ((int64_t)rc); } #ifndef FST_DYNAMIC_ALIAS2_DISABLE diff --git a/tests/data/malformed/chain_table_svarint_overlong.fst b/tests/data/malformed/chain_table_svarint_overlong.fst new file mode 100644 index 0000000..29427a6 Binary files /dev/null and b/tests/data/malformed/chain_table_svarint_overlong.fst differ diff --git a/tests/meson.build b/tests/meson.build index e7aa9e9..3dc087e 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -25,6 +25,7 @@ malformed_cases = [ 'chain_shorter_than_its_length', 'chain_table_overrun', 'chain_table_pair_unterminated', + 'chain_table_svarint_overlong', 'chain_table_unterminated', 'chain_uncompresses_past_traversal', 'chain_varint_pair_past_traversal', diff --git a/tests/reader_malformed_files.c b/tests/reader_malformed_files.c index 81e5bc2..c462c8e 100644 --- a/tests/reader_malformed_files.c +++ b/tests/reader_malformed_files.c @@ -33,6 +33,11 @@ * starts runs off the end of the table, reads as the zero that means * "this entry is two varints", and the second varint is not there * + * chain_table_svarint_overlong.fst + * a chain table holding two signed varints: one nine bytes long, ending + * at bit 63 with its sign bit set, and one eleven bytes long, with bit + * 63 set and bits past the 64th + * * chain_table_unterminated.fst * the last byte of a chain table asks for another byte, so a parse that * stops on reaching the end of the table exactly runs past it