Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-hiredis for openSUSE:Factory
checked in at 2026-10-06 19:15:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-hiredis (Old)
and /work/SRC/openSUSE:Factory/.python-hiredis.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-hiredis"
Tue Oct 6 19:15:03 2026 rev:18 rq:1382580 version:3.4.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-hiredis/python-hiredis.changes
2026-08-22 21:36:55.868898962 +0200
+++
/work/SRC/openSUSE:Factory/.python-hiredis.new.3698736/python-hiredis.changes
2026-10-06 19:16:07.266769297 +0200
@@ -1,0 +2,23 @@
+Mon Oct 5 16:26:56 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 3.4.2:
+ * Release the list each push notification is sized from
+ * `PushNotificationType_New` pre-sized every `PushNotification`
+ with a list that `PyList_SetSlice` only borrows, and the
+ reference was never dropped. Each RESP3 push notification
+ therefore stranded one list object for the lifetime of the
+ process. Because push notifications carry pub/sub deliveries
+ and client-side caching invalidations, the leak grew with
+ *message volume* rather than with the number of connections,
+ making it unbounded for a long-lived subscriber — roughly 20
+ MB per 200,000 four-element notifications, and more for
+ larger ones. Dropping the reference also removes an
+ allocation from the parse path, which makes parsing a small
+ notification about 10% faster.
+ * The same change checks `PyList_New` for failure and guards
+ `tryParentize` against a `NULL` reply, so an allocation
+ failure is now reported as an error instead of writing
+ elements past the end of a zero-length notification.
+ * RESP2 array replies were never affected.
+
+-------------------------------------------------------------------
Old:
----
hiredis-3.4.1.tar.gz
New:
----
hiredis-3.4.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-hiredis.spec ++++++
--- /var/tmp/diff_new_pack.hbtXRj/_old 2026-10-06 19:16:08.078803277 +0200
+++ /var/tmp/diff_new_pack.hbtXRj/_new 2026-10-06 19:16:08.079803319 +0200
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-hiredis
-Version: 3.4.1
+Version: 3.4.2
Release: 0
Summary: Python wrapper for hiredis
License: BSD-3-Clause
++++++ hiredis-3.4.1.tar.gz -> hiredis-3.4.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hiredis-3.4.1/PKG-INFO new/hiredis-3.4.2/PKG-INFO
--- old/hiredis-3.4.1/PKG-INFO 2026-08-07 10:46:41.959965000 +0200
+++ new/hiredis-3.4.2/PKG-INFO 2026-09-22 13:27:39.637731800 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: hiredis
-Version: 3.4.1
+Version: 3.4.2
Summary: Python wrapper for hiredis
Home-page: https://github.com/redis/hiredis-py
Author: Jan-Erik Rediger, Pieter Noordhuis
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hiredis-3.4.1/hiredis/version.py
new/hiredis-3.4.2/hiredis/version.py
--- old/hiredis-3.4.1/hiredis/version.py 2026-08-07 10:46:37.000000000
+0200
+++ new/hiredis-3.4.2/hiredis/version.py 2026-09-22 13:27:32.000000000
+0200
@@ -1 +1 @@
-__version__ = "3.4.1"
+__version__ = "3.4.2"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hiredis-3.4.1/hiredis.egg-info/PKG-INFO
new/hiredis-3.4.2/hiredis.egg-info/PKG-INFO
--- old/hiredis-3.4.1/hiredis.egg-info/PKG-INFO 2026-08-07 10:46:41.000000000
+0200
+++ new/hiredis-3.4.2/hiredis.egg-info/PKG-INFO 2026-09-22 13:27:39.000000000
+0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: hiredis
-Version: 3.4.1
+Version: 3.4.2
Summary: Python wrapper for hiredis
Home-page: https://github.com/redis/hiredis-py
Author: Jan-Erik Rediger, Pieter Noordhuis
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hiredis-3.4.1/src/reader.c
new/hiredis-3.4.2/src/reader.c
--- old/hiredis-3.4.1/src/reader.c 2026-08-07 10:46:37.000000000 +0200
+++ new/hiredis-3.4.2/src/reader.c 2026-09-22 13:27:32.000000000 +0200
@@ -83,6 +83,10 @@
static void *tryParentize(const redisReadTask *task, PyObject *obj) {
PyObject *parent;
+ if (obj == NULL) {
+ /* The caller failed to allocate; propagate so hiredis reports OOM. */
+ return NULL;
+ }
if (task && task->parent) {
parent = (PyObject*)task->parent->obj;
switch (task->parent->type) {
@@ -242,12 +246,22 @@
return NULL;
}
- int res = PyList_SetSlice(obj, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX,
PyList_New(size));
+ /* Pre-sizes the notification, whose elements are filled in as they parse.
+ * PyList_SetSlice does not steal a reference to the list it is handed, so
+ * it has to be released here. */
+ PyObject* items = PyList_New(size);
+ if (items == NULL) {
+ Py_DECREF(obj);
+ return NULL;
+ }
+
+ int res = PyList_SetSlice(obj, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, items);
+ Py_DECREF(items);
- if (res == -1) {
- Py_DECREF(obj);
- return NULL;
- }
+ if (res == -1) {
+ Py_DECREF(obj);
+ return NULL;
+ }
return obj;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hiredis-3.4.1/tests/test_reader.py
new/hiredis-3.4.2/tests/test_reader.py
--- old/hiredis-3.4.1/tests/test_reader.py 2026-08-07 10:46:37.000000000
+0200
+++ new/hiredis-3.4.2/tests/test_reader.py 2026-09-22 13:27:32.000000000
+0200
@@ -1,3 +1,6 @@
+import gc
+import platform
+
import hiredis
import pytest
@@ -191,6 +194,33 @@
assert isinstance(result, hiredis.PushNotification)
assert [b"pubsub", b"message", b"channel", b"message"] == result
[email protected](platform.python_implementation() != "CPython",
+ reason="requires CPython reference counting")
+def test_push_notification_releases_backing_list(reader):
+ # The list a notification is sized from is only borrowed by PyList_SetSlice,
+ # so not releasing it strands one list per notification received.
+ payload = b">4\r\n+pubsub\r\n+message\r\n+channel\r\n+message\r\n"
+ iterations = 512
+
+ def live_lists():
+ return sum(1 for obj in gc.get_objects() if type(obj) is list)
+
+ for _ in range(8):
+ reader.feed(payload)
+ reader.gets()
+ gc.collect()
+ before = live_lists()
+
+ for _ in range(iterations):
+ reader.feed(payload)
+ reader.gets()
+ gc.collect()
+
+ # Leaking strands exactly one list per iteration, so the bug reads as a delta
+ # of 512 where a fixed build measures 0. The bound is left far above 0 only
so
+ # that allocations elsewhere in the run cannot make this flaky.
+ assert live_lists() - before < iterations // 8
+
def test_verbatim_string(reader):
value = b"text"
reader.feed(b"=8\r\ntxt:%s\r\n" % value)