Skip to content

Commit 21a6e93

Browse files
bdracoasvetlov
andauthored
Fix segfault in PyType_GetModuleByDef for Python < 3.11 (#1141)
fixes #1140 --------- Co-authored-by: Andrew Svetlov <[email protected]>
1 parent 2c0d458 commit 21a6e93

File tree

4 files changed

+26
-5
lines changed

4 files changed

+26
-5
lines changed

CHANGES/1141.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed a segmentation fault when creating subclassed :py:class:`~multidict.MultiDict` objects on Python < 3.11 -- by :user:`bdraco`.
2+
3+
The problem first appeared in 6.4.0

docs/spelling_wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ runtime
8787
runtimes
8888
str
8989
subclassable
90+
subclassed
9091
subclassing
9192
subprotocol
9293
subprotocols

multidict/_multilib/state.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,14 @@ PyType_GetModuleByDef(PyTypeObject *tp, PyModuleDef *def)
6969

7070
Py_ssize_t n = PyTuple_GET_SIZE(mro);
7171
for (Py_ssize_t i = 1; i < n; i++) {
72-
mod = PyType_GetModule(tp);
73-
if (mod != NULL) {
72+
PyObject *super = PyTuple_GET_ITEM(mro, i);
73+
if (!PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) {
74+
continue;
75+
}
76+
mod = PyType_GetModule((PyTypeObject*)super);
77+
if (mod == NULL) {
7478
PyErr_Clear();
7579
} else {
76-
if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
77-
continue;
78-
}
7980
mod_def = PyModule_GetDef(mod);
8081
if (mod_def == def) {
8182
return mod;

tests/test_multidict.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,3 +1307,19 @@ def test_init_does_not_alter_refcount(
13071307
original_refcount = sys.getrefcount(original)
13081308
case_sensitive_multidict_class(original)
13091309
assert sys.getrefcount(original) == original_refcount
1310+
1311+
1312+
def test_subclassed_multidict(
1313+
any_multidict_class: type[MultiDict[str]],
1314+
) -> None:
1315+
"""Test that subclassed MultiDicts work as expected."""
1316+
class SubclassedMultiDict(any_multidict_class): # type: ignore[valid-type, misc]
1317+
"""Subclassed MultiDict."""
1318+
1319+
d1 = SubclassedMultiDict([("key", "value1")])
1320+
d2 = SubclassedMultiDict([("key", "value2")])
1321+
d3 = SubclassedMultiDict([("key", "value1")])
1322+
assert d1 != d2
1323+
assert d1 == d3
1324+
assert d1 == SubclassedMultiDict([("key", "value1")])
1325+
assert d1 != SubclassedMultiDict([("key", "value2")])

0 commit comments

Comments
 (0)