From 3d27eda8c63b3ef97c8b0e605d0cad2df57fd8c0 Mon Sep 17 00:00:00 2001 From: Cheruku Sri Charan Reddy <185475071+sricharanreddycheruku@users.noreply.github.com> Date: Wed, 7 Oct 2026 19:30:07 +0000 Subject: [PATCH] fix: avoid retaining Database.info results --- src/hyperscan/extension.c | 1 - tests/test_hyperscan.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/hyperscan/extension.c b/src/hyperscan/extension.c index e072d10..ecbe6ea 100644 --- a/src/hyperscan/extension.c +++ b/src/hyperscan/extension.c @@ -656,7 +656,6 @@ static PyObject *Database_info(Database *self, PyObject *args) } PyObject *oinfo = PyBytes_FromString(info); - Py_INCREF(oinfo); free(info); HS_LOCK_RETURN(oinfo); } diff --git a/tests/test_hyperscan.py b/tests/test_hyperscan.py index fcfac2d..4437a5e 100644 --- a/tests/test_hyperscan.py +++ b/tests/test_hyperscan.py @@ -1,3 +1,6 @@ +import sys +import tracemalloc + import pytest import hyperscan @@ -355,6 +358,35 @@ def test_database_info(database_block): assert field + b": " in info_string +@pytest.mark.skipif( + sys.implementation.name != "cpython", reason="requires CPython allocation tracing" +) +@pytest.mark.parametrize( + "db_fixture_name", + ["database_block", "database_stream", "database_vector", "database_chimera"], +) +def test_database_info_does_not_retain_results(db_fixture_name, request): + database = request.getfixturevalue(db_fixture_name) + database.info() + already_tracing = tracemalloc.is_tracing() + if not already_tracing: + tracemalloc.start() + try: + trace_filter = [tracemalloc.Filter(True, __file__)] + before = tracemalloc.take_snapshot().filter_traces(trace_filter) + for _ in range(1000): + database.info() + after = tracemalloc.take_snapshot().filter_traces(trace_filter) + retained = sum( + max(change.size_diff, 0) for change in after.compare_to(before, "lineno") + ) + # Allow tracing/loop bookkeeping; 1000 leaked results retain at least 70 KiB. + assert retained < 4096 + finally: + if not already_tracing: + tracemalloc.stop() + + @pytest.mark.parametrize( "db_fixture_name", ["database_stream", "database_block", "database_vector"],