Skip to content

Commit 6866bc9

Browse files
committed
gh-151673: Fix crash in warnings.warn() under memory pressure
1 parent 2e5843e commit 6866bc9

3 files changed

Lines changed: 36 additions & 3 deletions

File tree

Lib/test/test_warnings/__init__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
import warnings as original_warnings
2525
from warnings import deprecated
2626

27+
try:
28+
import _testcapi
29+
except ImportError:
30+
_testcapi = None
31+
2732

2833
py_warnings = import_helper.import_fresh_module('_py_warnings')
2934
py_warnings._set_module(py_warnings)
@@ -1237,6 +1242,24 @@ def test_issue31566(self):
12371242
support.swap_item(globals(), '__file__', None):
12381243
self.assertRaises(UserWarning, self.module.warn, 'bar')
12391244

1245+
@support.cpython_only
1246+
# Python built with Py_TRACE_REFS fail with a fatal error in
1247+
# _PyRefchain_Trace() on memory allocation error.
1248+
@unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build')
1249+
@unittest.skipIf(_testcapi is None, "requires _testcapi")
1250+
def test_issue151673(self):
1251+
# warn() shouldn't crash when the "<sys>" fallback filename
1252+
# can't be allocated under memory pressure.
1253+
code = """if 1:
1254+
import _testcapi, warnings
1255+
warnings.simplefilter("always")
1256+
_testcapi.set_nomemory(0)
1257+
warnings.warn("boom")
1258+
"""
1259+
rc, out, err = assert_python_failure("-c", code)
1260+
self.assertIn(rc, (1, 120))
1261+
self.assertIn(b'MemoryError', err)
1262+
12401263

12411264
class WarningsDisplayTests(BaseTest):
12421265

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a crash in :func:`warnings.warn` when the ``"<sys>"`` fallback filename
2+
could not be allocated under memory pressure: :c:func:`!setup_context` left
3+
the filename ``NULL`` and it was later passed to :c:func:`Py_DECREF`.

Python/_warnings.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,9 +1031,18 @@ setup_context(Py_ssize_t stack_level,
10311031
}
10321032
}
10331033

1034+
/* Initialize the output references so handle_error can Py_XDECREF them
1035+
even when we bail out before they are assigned. */
1036+
*filename = NULL;
1037+
*registry = NULL;
1038+
*module = NULL;
1039+
10341040
if (f == NULL) {
10351041
globals = interp->sysdict;
10361042
*filename = PyUnicode_FromString("<sys>");
1043+
if (*filename == NULL) {
1044+
goto handle_error;
1045+
}
10371046
*lineno = 0;
10381047
}
10391048
else {
@@ -1043,8 +1052,6 @@ setup_context(Py_ssize_t stack_level,
10431052
Py_DECREF(f);
10441053
}
10451054

1046-
*module = NULL;
1047-
10481055
/* Setup registry. */
10491056
assert(globals != NULL);
10501057
assert(PyAnyDict_Check(globals));
@@ -1084,7 +1091,7 @@ setup_context(Py_ssize_t stack_level,
10841091
handle_error:
10851092
Py_XDECREF(*registry);
10861093
Py_XDECREF(*module);
1087-
Py_DECREF(*filename);
1094+
Py_XDECREF(*filename);
10881095
return 0;
10891096
}
10901097

0 commit comments

Comments
 (0)