diff --git a/CMakeLists.txt b/CMakeLists.txt index abbfe53b..b0094d94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project (Hyperscan C CXX) set (HS_MAJOR_VERSION 4) set (HS_MINOR_VERSION 3) -set (HS_PATCH_VERSION 0) +set (HS_PATCH_VERSION 1) set (HS_VERSION ${HS_MAJOR_VERSION}.${HS_MINOR_VERSION}.${HS_PATCH_VERSION}) # since we are doing this manually, we only have three types diff --git a/src/runtime.c b/src/runtime.c index 35a11634..e761acc2 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -466,16 +466,19 @@ void maintainHistoryBuffer(const struct RoseEngine *rose, char *state, } static really_inline -void init_stream(struct hs_stream *s, const struct RoseEngine *rose) { +void init_stream(struct hs_stream *s, const struct RoseEngine *rose, + char init_history) { char *state = getMultiState(s); - // Make absolutely sure that the 16 bytes leading up to the end of the - // history buffer are initialised, as we rely on this (regardless of the - // actual values used) in FDR. - char *hist_end = state + rose->stateOffsets.history + rose->historyRequired; - assert(hist_end - 16 >= (const char *)s); - unaligned_store_u64a(hist_end - 16, 0xDEADDEADDEADDEADull); - unaligned_store_u64a(hist_end - 8, 0xDEADDEADDEADDEADull); + if (init_history) { + // Make absolutely sure that the 16 bytes leading up to the end of the + // history buffer are initialised, as we rely on this (regardless of the + // actual values used) in FDR. + char *hist_end = + state + rose->stateOffsets.history + rose->historyRequired; + assert(hist_end - 16 >= (const char *)s); + memset(hist_end - 16, 0x5a, 16); + } s->rose = rose; s->offset = 0; @@ -518,7 +521,7 @@ hs_error_t hs_open_stream(const hs_database_t *db, UNUSED unsigned flags, return HS_NOMEM; } - init_stream(s, rose); + init_stream(s, rose, 1); *stream = s; return HS_SUCCESS; @@ -962,7 +965,8 @@ hs_error_t hs_reset_stream(hs_stream_t *id, UNUSED unsigned int flags, unmarkScratchInUse(scratch); } - init_stream(id, id->rose); + // history already initialised + init_stream(id, id->rose, 0); return HS_SUCCESS; } @@ -1047,7 +1051,7 @@ hs_error_t hs_scan_vector(const hs_database_t *db, const char * const * data, hs_stream_t *id = (hs_stream_t *)(scratch->bstate); - init_stream(id, rose); /* open stream */ + init_stream(id, rose, 1); /* open stream */ for (u32 i = 0; i < count; i++) { DEBUG_PRINTF("block %u/%u offset=%llu len=%u\n", i, count, id->offset, diff --git a/unit/hyperscan/stream_op.cpp b/unit/hyperscan/stream_op.cpp index 48cb6b8d..339f5463 100644 --- a/unit/hyperscan/stream_op.cpp +++ b/unit/hyperscan/stream_op.cpp @@ -157,6 +157,45 @@ TEST(StreamUtil, reset_matches) { hs_free_database(db); } +TEST(StreamUtil, reset_close) { + hs_error_t err; + hs_scratch_t *scratch = nullptr; + hs_database_t *db = buildDBAndScratch("foo", 0, 0, HS_MODE_STREAM, + &scratch); + + hs_stream_t *stream = nullptr; + CallBackContext c; + + err = hs_open_stream(db, 0, &stream); + ASSERT_EQ(HS_SUCCESS, err); + ASSERT_TRUE(stream != nullptr); + + // break matching string over two stream writes + const char part1[] = "---f"; + err = hs_scan_stream(stream, part1, strlen(part1), 0, scratch, record_cb, + (void *)&c); + ASSERT_EQ(HS_SUCCESS, err); + ASSERT_EQ(0U, c.matches.size()); + + const char part2[] = "oo--"; + err = hs_scan_stream(stream, part2, strlen(part2), 0, scratch, record_cb, + (void *)&c); + ASSERT_EQ(HS_SUCCESS, err); + ASSERT_EQ(1U, c.matches.size()); + ASSERT_EQ(MatchRecord(6, 0), c.matches[0]); + + err = hs_reset_stream(stream, 0, scratch, record_cb, (void *)&c); + ASSERT_EQ(HS_SUCCESS, err); + // still only one match + ASSERT_EQ(1U, c.matches.size()); + + err = hs_close_stream(stream, scratch, record_cb, (void *)&c); + ASSERT_EQ(HS_SUCCESS, err); + err = hs_free_scratch(scratch); + ASSERT_EQ(HS_SUCCESS, err); + hs_free_database(db); +} + TEST(StreamUtil, copy1) { hs_error_t err; hs_scratch_t *scratch = nullptr;