diff --git a/src/hs_runtime.h b/src/hs_runtime.h index 27de00a3..db52f4f5 100644 --- a/src/hs_runtime.h +++ b/src/hs_runtime.h @@ -250,7 +250,8 @@ hs_error_t hs_close_stream(hs_stream_t *id, hs_scratch_t *scratch, * for future use and is unused at present. * * @param scratch - * A per-thread scratch space allocated by @ref hs_alloc_scratch(). + * A per-thread scratch space allocated by @ref hs_alloc_scratch(). This is + * allowed to be NULL only if the @a onEvent callback is also NULL. * * @param onEvent * Pointer to a match event callback function. If a NULL pointer is given, @@ -299,7 +300,8 @@ hs_error_t hs_copy_stream(hs_stream_t **to_id, const hs_stream_t *from_id); * The stream (as created by @ref hs_open_stream()) to be copied. * * @param scratch - * A per-thread scratch space allocated by @ref hs_alloc_scratch(). + * A per-thread scratch space allocated by @ref hs_alloc_scratch(). This is + * allowed to be NULL only if the @a onEvent callback is also NULL. * * @param onEvent * Pointer to a match event callback function. If a NULL pointer is given, diff --git a/src/runtime.c b/src/runtime.c index 66323789..335a83bc 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -1163,11 +1163,10 @@ hs_error_t hs_reset_and_copy_stream(hs_stream_t *to_id, return HS_INVALID; } - if (!scratch || !validScratch(to_id->rose, scratch)) { - return HS_INVALID; - } - if (onEvent) { + if (!scratch || !validScratch(to_id->rose, scratch)) { + return HS_INVALID; + } report_eod_matches(to_id, scratch, onEvent, context); } @@ -1406,12 +1405,14 @@ HS_PUBLIC_API hs_error_t hs_reset_stream(hs_stream_t *id, UNUSED unsigned int flags, hs_scratch_t *scratch, match_event_handler onEvent, void *context) { - if (!id || !scratch || !validScratch(id->rose, scratch)) { + if (!id) { return HS_INVALID; } - /* user wants eod matches */ if (onEvent) { + if (!scratch || !validScratch(id->rose, scratch)) { + return HS_INVALID; + } report_eod_matches(id, scratch, onEvent, context); } diff --git a/unit/hyperscan/arg_checks.cpp b/unit/hyperscan/arg_checks.cpp index f717f0dc..dbc692c5 100644 --- a/unit/hyperscan/arg_checks.cpp +++ b/unit/hyperscan/arg_checks.cpp @@ -740,7 +740,9 @@ TEST(HyperscanArgChecks, ResetAndCopyStreamSameToId) { hs_free_database(db); } -TEST(HyperscanArgChecks, ResetAndCopyStreamNoScratch) { +// hs_reset_and_copy_stream: You're allowed to reset and copy a stream with no +// scratch and no callback. +TEST(HyperscanArgChecks, ResetAndCopyStreamNoCallbackOrScratch) { hs_stream_t *stream = nullptr; hs_stream_t *stream_to = nullptr; hs_database_t *db = nullptr; @@ -760,6 +762,37 @@ TEST(HyperscanArgChecks, ResetAndCopyStreamNoScratch) { ASSERT_EQ(HS_SUCCESS, err); err = hs_reset_and_copy_stream(stream_to, stream, nullptr, nullptr, nullptr); + ASSERT_EQ(HS_SUCCESS, err); + + hs_close_stream(stream_to, scratch, nullptr, nullptr); + hs_close_stream(stream, scratch, nullptr, nullptr); + hs_free_scratch(scratch); + hs_free_database(db); +} + +// hs_reset_and_copy_stream: If you specify a callback, you must provide +// scratch. +TEST(HyperscanArgChecks, ResetAndCopyStreamNoScratch) { + hs_stream_t *stream = nullptr; + hs_stream_t *stream_to = nullptr; + hs_database_t *db = nullptr; + hs_compile_error_t *compile_err = nullptr; + hs_error_t err = hs_compile("foobar", 0, HS_MODE_STREAM, nullptr, &db, + &compile_err); + ASSERT_EQ(HS_SUCCESS, err); + + hs_scratch_t *scratch = nullptr; + err = hs_alloc_scratch(db, &scratch); + ASSERT_EQ(HS_SUCCESS, err); + + err = hs_open_stream(db, 0, &stream); + ASSERT_EQ(HS_SUCCESS, err); + + err = hs_open_stream(db, 0, &stream_to); + ASSERT_EQ(HS_SUCCESS, err); + + err = hs_reset_and_copy_stream(stream_to, stream, nullptr, dummy_cb, + nullptr); ASSERT_EQ(HS_INVALID, err); hs_close_stream(stream_to, scratch, nullptr, nullptr); @@ -793,7 +826,8 @@ TEST(HyperscanArgChecks, ResetAndCopyStreamDiffDb) { err = hs_open_stream(db2, 0, &stream_to); ASSERT_EQ(HS_SUCCESS, err); - err = hs_reset_and_copy_stream(stream_to, stream, scratch, nullptr, nullptr); + err = hs_reset_and_copy_stream(stream_to, stream, scratch, nullptr, + nullptr); ASSERT_EQ(HS_INVALID, err); hs_close_stream(stream_to, scratch, nullptr, nullptr); @@ -2009,6 +2043,7 @@ TEST(HyperscanArgChecks, ScanStreamBadScratch) { free(local_garbage); } +// hs_reset_stream: bad scratch arg TEST(HyperscanArgChecks, ResetStreamBadScratch) { hs_database_t *db = nullptr; hs_compile_error_t *compile_err = nullptr; @@ -2025,7 +2060,7 @@ TEST(HyperscanArgChecks, ResetStreamBadScratch) { ASSERT_EQ(HS_SUCCESS, err); ASSERT_TRUE(stream != nullptr); - err = hs_reset_stream(stream, 0, scratch, nullptr, nullptr); + err = hs_reset_stream(stream, 0, scratch, dummy_cb, nullptr); EXPECT_NE(HS_SUCCESS, err); EXPECT_NE(HS_SCAN_TERMINATED, err); diff --git a/unit/hyperscan/stream_op.cpp b/unit/hyperscan/stream_op.cpp index fbec6b98..a78e08a1 100644 --- a/unit/hyperscan/stream_op.cpp +++ b/unit/hyperscan/stream_op.cpp @@ -69,7 +69,9 @@ TEST(StreamUtil, reset1) { c.matches.clear(); - err = hs_reset_stream(stream, 0, scratch, nullptr, nullptr); + // Note: we do not need matches from this reset operation, so we do not + // need to supply a callback or scratch space. + err = hs_reset_stream(stream, 0, nullptr, nullptr, nullptr); ASSERT_EQ(HS_SUCCESS, err); err = hs_scan_stream(stream, data1, sizeof(data1), 0, scratch, record_cb2, @@ -107,7 +109,9 @@ TEST(StreamUtil, reset2) { c.matches.clear(); - err = hs_reset_stream(stream, 0, scratch, nullptr, nullptr); + // Note: we do not need matches from this reset operation, so we do not + // need to supply a callback or scratch space. + err = hs_reset_stream(stream, 0, nullptr, nullptr, nullptr); ASSERT_EQ(HS_SUCCESS, err); err = hs_scan_stream(stream, data1, sizeof(data1), 0, scratch, record_cb, @@ -268,7 +272,7 @@ TEST(StreamUtil, copy_reset1) { c.matches.clear(); - err = hs_reset_and_copy_stream(stream, stream2, scratch, nullptr, nullptr); + err = hs_reset_and_copy_stream(stream, stream2, nullptr, nullptr, nullptr); ASSERT_EQ(HS_SUCCESS, err); err = hs_scan_stream(stream, data1, sizeof(data1), 0, scratch, record_cb2, @@ -312,7 +316,7 @@ TEST(StreamUtil, copy_reset2) { c.matches.clear(); - err = hs_reset_and_copy_stream(stream, stream2, scratch, nullptr, nullptr); + err = hs_reset_and_copy_stream(stream, stream2, nullptr, nullptr, nullptr); ASSERT_EQ(HS_SUCCESS, err); err = hs_scan_stream(stream, data1, sizeof(data1), 0, scratch, record_cb, @@ -355,7 +359,7 @@ TEST(StreamUtil, copy_reset3) { c.matches.clear(); - err = hs_reset_and_copy_stream(stream2, stream, scratch, nullptr, nullptr); + err = hs_reset_and_copy_stream(stream2, stream, nullptr, nullptr, nullptr); ASSERT_EQ(HS_SUCCESS, err); err = hs_scan_stream(stream, data1, sizeof(data1), 0, scratch, record_cb, @@ -408,7 +412,7 @@ TEST(StreamUtil, copy_reset4) { c.matches.clear(); - err = hs_reset_and_copy_stream(stream2, stream, scratch, nullptr, nullptr); + err = hs_reset_and_copy_stream(stream2, stream, nullptr, nullptr, nullptr); ASSERT_EQ(HS_SUCCESS, err); err = hs_scan_stream(stream, data1, sizeof(data1), 0, scratch, record_cb, @@ -458,7 +462,7 @@ TEST(StreamUtil, copy_reset5) { ASSERT_EQ(HS_SUCCESS, err); ASSERT_EQ(0U, c.matches.size()); - err = hs_reset_and_copy_stream(stream2, stream, scratch, nullptr, nullptr); + err = hs_reset_and_copy_stream(stream2, stream, nullptr, nullptr, nullptr); ASSERT_EQ(HS_SUCCESS, err); err = hs_scan_stream(stream, data1, sizeof(data1), 0, scratch, record_cb,