Skip to content

Commit 512523a

Browse files
committed
Merge branch 'main' of https://github.com/python/cpython into fix.missing.venv.home
2 parents adca94b + 621a8bd commit 512523a

36 files changed

+906
-757
lines changed

Doc/c-api/extension-modules.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,6 @@ in the following ways:
242242
* Single-phase modules support module lookup functions like
243243
:c:func:`PyState_FindModule`.
244244

245-
.. [#testsinglephase] ``_testsinglephase`` is an internal module used \
246-
in CPython's self-test suite; your installation may or may not \
245+
.. [#testsinglephase] ``_testsinglephase`` is an internal module used
246+
in CPython's self-test suite; your installation may or may not
247247
include it.

Doc/library/dialog.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ is the base class for dialogs defined in other supporting modules.
220220

221221
.. class:: Dialog(master=None, **options)
222222

223-
.. method:: show(color=None, **options)
223+
.. method:: show(**options)
224224

225225
Render the Dialog window.
226226

Doc/library/netrc.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ the Unix :program:`ftp` program and other FTP clients.
2424
a :exc:`FileNotFoundError` exception will be raised.
2525
Parse errors will raise :exc:`NetrcParseError` with diagnostic
2626
information including the file name, line number, and terminating token.
27+
2728
If no argument is specified on a POSIX system, the presence of passwords in
2829
the :file:`.netrc` file will raise a :exc:`NetrcParseError` if the file
2930
ownership or permissions are insecure (owned by a user other than the user
3031
running the process, or accessible for read or write by any other user).
3132
This implements security behavior equivalent to that of ftp and other
32-
programs that use :file:`.netrc`.
33+
programs that use :file:`.netrc`. Such security checks are not available
34+
on platforms that do not support :func:`os.getuid`.
3335

3436
.. versionchanged:: 3.4 Added the POSIX permission check.
3537

Doc/library/sys.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,15 @@ always available. Unless explicitly noted otherwise, all variables are read-only
11851185
``cache_tag`` is set to ``None``, it indicates that module caching should
11861186
be disabled.
11871187

1188+
*supports_isolated_interpreters* is a boolean value, whether
1189+
this implementation supports multiple isolated interpreters.
1190+
It is ``True`` for CPython on most platforms. Platforms with
1191+
this support implement the low-level :mod:`!_interpreters` module.
1192+
1193+
.. seealso::
1194+
1195+
:pep:`684`, :pep:`734`, and :mod:`concurrent.interpreters`.
1196+
11881197
:data:`sys.implementation` may contain additional attributes specific to
11891198
the Python implementation. These non-standard attributes must start with
11901199
an underscore, and are not described here. Regardless of its contents,
@@ -1194,6 +1203,9 @@ always available. Unless explicitly noted otherwise, all variables are read-only
11941203

11951204
.. versionadded:: 3.3
11961205

1206+
.. versionchanged:: 3.14
1207+
Added ``supports_isolated_interpreters`` field.
1208+
11971209
.. note::
11981210

11991211
The addition of new required attributes must go through the normal PEP

Include/internal/pycore_critical_section.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ extern "C" {
6464

6565
# define _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op) \
6666
if (Py_REFCNT(op) != 1) { \
67-
_Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(&_PyObject_CAST(op)->ob_mutex); \
67+
_PyCriticalSection_AssertHeldObj(_PyObject_CAST(op)); \
6868
}
6969

7070
#else /* Py_DEBUG */
@@ -239,6 +239,28 @@ _PyCriticalSection_AssertHeld(PyMutex *mutex)
239239
#endif
240240
}
241241

242+
static inline void
243+
_PyCriticalSection_AssertHeldObj(PyObject *op)
244+
{
245+
#ifdef Py_DEBUG
246+
PyMutex *mutex = &_PyObject_CAST(op)->ob_mutex;
247+
PyThreadState *tstate = _PyThreadState_GET();
248+
uintptr_t prev = tstate->critical_section;
249+
if (prev & _Py_CRITICAL_SECTION_TWO_MUTEXES) {
250+
PyCriticalSection2 *cs = (PyCriticalSection2 *)(prev & ~_Py_CRITICAL_SECTION_MASK);
251+
_PyObject_ASSERT_WITH_MSG(op,
252+
(cs != NULL && (cs->_cs_base._cs_mutex == mutex || cs->_cs_mutex2 == mutex)),
253+
"Critical section of object is not held");
254+
}
255+
else {
256+
PyCriticalSection *cs = (PyCriticalSection *)(prev & ~_Py_CRITICAL_SECTION_MASK);
257+
_PyObject_ASSERT_WITH_MSG(op,
258+
(cs != NULL && cs->_cs_mutex == mutex),
259+
"Critical section of object is not held");
260+
}
261+
262+
#endif
263+
}
242264
#endif /* Py_GIL_DISABLED */
243265

244266
#ifdef __cplusplus

Lib/netrc.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@
77
__all__ = ["netrc", "NetrcParseError"]
88

99

10+
def _can_security_check():
11+
# On WASI, getuid() is indicated as a stub but it may also be missing.
12+
return os.name == 'posix' and hasattr(os, 'getuid')
13+
14+
15+
def _getpwuid(uid):
16+
try:
17+
import pwd
18+
return pwd.getpwuid(uid)[0]
19+
except (ImportError, LookupError):
20+
return f'uid {uid}'
21+
22+
1023
class NetrcParseError(Exception):
1124
"""Exception raised on syntax errors in the .netrc file."""
1225
def __init__(self, msg, filename=None, lineno=None):
@@ -142,18 +155,12 @@ def _parse(self, file, fp, default_netrc):
142155
self._security_check(fp, default_netrc, self.hosts[entryname][0])
143156

144157
def _security_check(self, fp, default_netrc, login):
145-
if os.name == 'posix' and default_netrc and login != "anonymous":
158+
if _can_security_check() and default_netrc and login != "anonymous":
146159
prop = os.fstat(fp.fileno())
147-
if prop.st_uid != os.getuid():
148-
import pwd
149-
try:
150-
fowner = pwd.getpwuid(prop.st_uid)[0]
151-
except KeyError:
152-
fowner = 'uid %s' % prop.st_uid
153-
try:
154-
user = pwd.getpwuid(os.getuid())[0]
155-
except KeyError:
156-
user = 'uid %s' % os.getuid()
160+
current_user_id = os.getuid()
161+
if prop.st_uid != current_user_id:
162+
fowner = _getpwuid(prop.st_uid)
163+
user = _getpwuid(current_user_id)
157164
raise NetrcParseError(
158165
(f"~/.netrc file owner ({fowner}, {user}) does not match"
159166
" current user"))

Lib/test/libregrtest/tsan.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
'test_capi.test_pyatomic',
99
'test_code',
1010
'test_ctypes',
11-
# 'test_concurrent_futures', # gh-130605: too many data races
11+
'test_concurrent_futures',
1212
'test_enum',
1313
'test_functools',
1414
'test_httpservers',

Lib/test/test_capi/test_misc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,11 +413,13 @@ def test_trashcan_subclass(self):
413413

414414
@support.requires_resource('cpu')
415415
@support.skip_emscripten_stack_overflow()
416+
@support.skip_wasi_stack_overflow()
416417
def test_trashcan_python_class1(self):
417418
self.do_test_trashcan_python_class(list)
418419

419420
@support.requires_resource('cpu')
420421
@support.skip_emscripten_stack_overflow()
422+
@support.skip_wasi_stack_overflow()
421423
def test_trashcan_python_class2(self):
422424
from _testcapi import MyList
423425
self.do_test_trashcan_python_class(MyList)

Lib/test/test_capi/test_opt.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,6 +1968,49 @@ def testfunc(n):
19681968
self.assertNotIn("_GUARD_NOS_INT", uops)
19691969
self.assertNotIn("_GUARD_TOS_INT", uops)
19701970

1971+
def test_call_len_known_length_small_int(self):
1972+
def testfunc(n):
1973+
x = 0
1974+
for _ in range(n):
1975+
t = (1, 2, 3, 4, 5)
1976+
if len(t) == 5:
1977+
x += 1
1978+
return x
1979+
1980+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
1981+
self.assertEqual(res, TIER2_THRESHOLD)
1982+
self.assertIsNotNone(ex)
1983+
uops = get_opnames(ex)
1984+
# When the length is < _PY_NSMALLPOSINTS, the len() call is replaced
1985+
# with just an inline load.
1986+
self.assertNotIn("_CALL_LEN", uops)
1987+
self.assertNotIn("_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW", uops)
1988+
self.assertNotIn("_POP_CALL_LOAD_CONST_INLINE_BORROW", uops)
1989+
self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops)
1990+
1991+
def test_call_len_known_length(self):
1992+
def testfunc(n):
1993+
class C:
1994+
t = tuple(range(300))
1995+
1996+
x = 0
1997+
for _ in range(n):
1998+
if len(C.t) == 300: # comparison + guard removed
1999+
x += 1
2000+
return x
2001+
2002+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
2003+
self.assertEqual(res, TIER2_THRESHOLD)
2004+
self.assertIsNotNone(ex)
2005+
uops = get_opnames(ex)
2006+
# When the length is >= _PY_NSMALLPOSINTS, we cannot replace
2007+
# the len() call with an inline load, but knowing the exact
2008+
# length allows us to optimize more code, such as conditionals
2009+
# in this case
2010+
self.assertIn("_CALL_LEN", uops)
2011+
self.assertNotIn("_COMPARE_OP_INT", uops)
2012+
self.assertNotIn("_GUARD_IS_TRUE_POP", uops)
2013+
19712014
def test_get_len_with_const_tuple(self):
19722015
def testfunc(n):
19732016
x = 0.0

Lib/test/test_free_threading/test_heapq.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import heapq
44

55
from enum import Enum
6-
from threading import Thread, Barrier
6+
from threading import Thread, Barrier, Lock
77
from random import shuffle, randint
88

99
from test.support import threading_helper
@@ -178,6 +178,33 @@ def heapreplace_max_func(max_heap, replace_items):
178178
self.assertEqual(len(max_heap), OBJECT_COUNT)
179179
self.test_heapq.check_max_invariant(max_heap)
180180

181+
def test_lock_free_list_read(self):
182+
n, n_threads = 1_000, 10
183+
l = []
184+
barrier = Barrier(n_threads * 2)
185+
186+
count = 0
187+
lock = Lock()
188+
189+
def worker():
190+
with lock:
191+
nonlocal count
192+
x = count
193+
count += 1
194+
195+
barrier.wait()
196+
for i in range(n):
197+
if x % 2:
198+
heapq.heappush(l, 1)
199+
heapq.heappop(l)
200+
else:
201+
try:
202+
l[0]
203+
except IndexError:
204+
pass
205+
206+
self.run_concurrently(worker, (), n_threads * 2)
207+
181208
@staticmethod
182209
def is_sorted_ascending(lst):
183210
"""

0 commit comments

Comments
 (0)