Skip to content

Commit 9c964f9

Browse files
authored
Merge branch 'main' into json_ft
2 parents 0424c58 + 4e6f0d1 commit 9c964f9

7 files changed

Lines changed: 53 additions & 15 deletions

File tree

Doc/using/cmdline.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,13 @@ Miscellaneous options
669669

670670
.. versionadded:: 3.14
671671

672+
* :samp:`-X tlbc={0,1}` enables (1, the default) or disables (0) thread-local
673+
bytecode in builds configured with :option:`--disable-gil`. When disabled,
674+
this also disables the specializing interpreter. See also
675+
:envvar:`PYTHON_TLBC`.
676+
677+
.. versionadded:: 3.14
678+
672679
It also allows passing arbitrary values and retrieving them through the
673680
:data:`sys._xoptions` dictionary.
674681

@@ -1302,6 +1309,16 @@ conflict.
13021309

13031310
.. versionadded:: 3.13
13041311

1312+
.. envvar:: PYTHON_TLBC
1313+
1314+
If set to ``1`` enables thread-local bytecode. If set to ``0`` thread-local
1315+
bytecode and the specializing interpreter are disabled. Only applies to
1316+
builds configured with :option:`--disable-gil`.
1317+
1318+
See also the :option:`-X tlbc <-X>` command-line option.
1319+
1320+
.. versionadded:: 3.14
1321+
13051322
Debug-mode variables
13061323
~~~~~~~~~~~~~~~~~~~~
13071324

Lib/test/test__interpreters.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,21 @@ def test_signatures(self):
485485
msg = r'_interpreters.run_func\(\) argument 3 must be dict, not int'
486486
with self.assertRaisesRegex(TypeError, msg):
487487
_interpreters.run_func(self.id, lambda: None, shared=1)
488+
# See https://github.com/python/cpython/issues/135855
489+
msg = r'_interpreters.set___main___attrs\(\) argument 2 must be dict, not int'
490+
with self.assertRaisesRegex(TypeError, msg):
491+
_interpreters.set___main___attrs(self.id, 1)
492+
493+
def test_invalid_shared_none(self):
494+
msg = r'must be dict, not None'
495+
with self.assertRaisesRegex(TypeError, msg):
496+
_interpreters.exec(self.id, 'a', shared=None)
497+
with self.assertRaisesRegex(TypeError, msg):
498+
_interpreters.run_string(self.id, 'a', shared=None)
499+
with self.assertRaisesRegex(TypeError, msg):
500+
_interpreters.run_func(self.id, lambda: None, shared=None)
501+
with self.assertRaisesRegex(TypeError, msg):
502+
_interpreters.set___main___attrs(self.id, None)
488503

489504
def test_invalid_shared_encoding(self):
490505
# See https://github.com/python/cpython/issues/127196
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Raise :exc:`TypeError` instead of :exc:`SystemError` when
2+
:func:`!_interpreters.set___main___attrs` is passed a non-dict object.
3+
Patch by Brian Schubert.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixes a crash of :class:`types.SimpleNamespace` on :term:`free threading` builds,
2+
when several threads were calling its :meth:`~object.__repr__` method at the
3+
same time.

Modules/_interpretersmodule.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,8 +1039,8 @@ interp_set___main___attrs(PyObject *self, PyObject *args, PyObject *kwargs)
10391039
PyObject *id, *updates;
10401040
int restricted = 0;
10411041
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
1042-
"OO|$p:" MODULE_NAME_STR ".set___main___attrs",
1043-
kwlist, &id, &updates, &restricted))
1042+
"OO!|$p:" MODULE_NAME_STR ".set___main___attrs",
1043+
kwlist, &id, &PyDict_Type, &updates, &restricted))
10441044
{
10451045
return NULL;
10461046
}
@@ -1054,16 +1054,14 @@ interp_set___main___attrs(PyObject *self, PyObject *args, PyObject *kwargs)
10541054
}
10551055

10561056
// Check the updates.
1057-
if (updates != Py_None) {
1058-
Py_ssize_t size = PyObject_Size(updates);
1059-
if (size < 0) {
1060-
return NULL;
1061-
}
1062-
if (size == 0) {
1063-
PyErr_SetString(PyExc_ValueError,
1064-
"arg 2 must be a non-empty mapping");
1065-
return NULL;
1066-
}
1057+
Py_ssize_t size = PyDict_Size(updates);
1058+
if (size < 0) {
1059+
return NULL;
1060+
}
1061+
if (size == 0) {
1062+
PyErr_SetString(PyExc_ValueError,
1063+
"arg 2 must be a non-empty dict");
1064+
return NULL;
10671065
}
10681066

10691067
_PyXI_session *session = _PyXI_NewSession();

Objects/namespaceobject.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,10 @@ namespace_repr(PyObject *ns)
124124
if (PyUnicode_Check(key) && PyUnicode_GET_LENGTH(key) > 0) {
125125
PyObject *value, *item;
126126

127-
value = PyDict_GetItemWithError(d, key);
128-
if (value != NULL) {
127+
int has_key = PyDict_GetItemRef(d, key, &value);
128+
if (has_key == 1) {
129129
item = PyUnicode_FromFormat("%U=%R", key, value);
130+
Py_DECREF(value);
130131
if (item == NULL) {
131132
loop_error = 1;
132133
}
@@ -135,7 +136,7 @@ namespace_repr(PyObject *ns)
135136
Py_DECREF(item);
136137
}
137138
}
138-
else if (PyErr_Occurred()) {
139+
else if (has_key < 0) {
139140
loop_error = 1;
140141
}
141142
}

Python/crossinterp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2617,6 +2617,7 @@ _PyXI_Enter(_PyXI_session *session,
26172617
// Convert the attrs for cross-interpreter use.
26182618
_PyXI_namespace *sharedns = NULL;
26192619
if (nsupdates != NULL) {
2620+
assert(PyDict_Check(nsupdates));
26202621
Py_ssize_t len = PyDict_Size(nsupdates);
26212622
if (len < 0) {
26222623
if (result != NULL) {

0 commit comments

Comments
 (0)