diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 698f2117ff5c649..ff38ba395fba22c 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -152,10 +152,11 @@ Alpha, beta and release candidate versions have an additional suffix: In other words, all versions labeled *2.0aN* precede the versions labeled *2.0bN*, which precede versions labeled *2.0rcN*, and *those* precede 2.0. -You may also find version numbers with a "+" suffix, e.g. "2.2+". These are -unreleased versions, built directly from the CPython development repository. In -practice, after a final minor release is made, the version is incremented to the -next minor version, which becomes the "a0" version, e.g. "2.4a0". +You may also find version numbers with a "+dev" suffix, such as "3.15.0b3+dev". +These are unreleased versions, built directly from the CPython development +repository. After the first beta release is made, the version is +incremented to the next feature version, which becomes the "a0" version, +such as "3.16.0a0". See the `Developer's Guide `__ diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index b9b76a44e3b4e79..d62194acd9c29e5 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -50,6 +50,14 @@ def setup_process() -> None: for signum in signals: faulthandler.register(signum, chain=True, file=stderr_fd) + # Restore the default SIGINT handler if there is no Python-level + # handler. Python inherits the SIG_IGN disposition when the test + # suite runs as a shell background job; then asyncio.Runner does not + # install its own handler and _thread.interrupt_main() is a no-op, + # which makes some tests in test_asyncio and test_threading hang. + if signal.getsignal(signal.SIGINT) in (signal.SIG_IGN, signal.SIG_DFL): + signal.signal(signal.SIGINT, signal.default_int_handler) + adjust_rlimit_nofile() support.record_original_stdout(sys.stdout) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 2e2ac147968dd4a..55c6ad04d44d828 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -907,9 +907,10 @@ def test_resize_up_anonymous_mapping(self): with mmap.mmap(-1, start_size) as m: m[:] = data - if sys.platform.startswith(('linux', 'android')): - # Can't expand a shared anonymous mapping on Linux. - # See https://bugzilla.kernel.org/show_bug.cgi?id=8691 + if sys.platform.startswith(('linux', 'android', 'netbsd')): + # Can't expand a shared anonymous mapping on Linux + # (see https://bugzilla.kernel.org/show_bug.cgi?id=8691) + # or NetBSD. with self.assertRaises(ValueError): m.resize(new_size) else: @@ -1175,8 +1176,8 @@ def test_flush_parameters(self): if hasattr(mmap, 'MS_INVALIDATE'): m.flush(PAGESIZE * 2, flags=mmap.MS_INVALIDATE) if hasattr(mmap, 'MS_ASYNC') and hasattr(mmap, 'MS_INVALIDATE'): - if sys.platform == 'freebsd': - # FreeBSD doesn't support this combination + if sys.platform.startswith(('freebsd', 'dragonfly')): + # FreeBSD and DragonFly don't support this combination with self.assertRaises(OSError) as cm: m.flush(0, PAGESIZE, flags=mmap.MS_ASYNC | mmap.MS_INVALIDATE) self.assertEqual(cm.exception.errno, errno.EINVAL) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 299e7212966ae3d..99f9e746c854e32 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -59,6 +59,9 @@ # SCM_RIGHTS control message when several are sent in a single sendmsg(). BSD_COMBINES_SCM_RIGHTS = sys.platform.startswith( ("netbsd", "openbsd", "dragonfly")) +# OpenBSD and DragonFly fail recvmsg() with EMSGSIZE, instead of setting +# MSG_CTRUNC, when the ancillary data buffer is too small for a cmsghdr. +CMSG_TRUNC_RAISES_EMSGSIZE = sys.platform.startswith(("openbsd", "dragonfly")) WSL = "microsoft-standard-WSL" in platform.release() try: @@ -4351,6 +4354,7 @@ def _testCmsgTrunc0(self): # (but still too small) buffer sizes. @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTrunc1(self): self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 1)) @@ -4359,6 +4363,7 @@ def _testCmsgTrunc1(self): self.createAndSendFDs(1) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTrunc2Int(self): # The cmsghdr structure has at least three members, two of # which are ints, so we still shouldn't see any ancillary @@ -4371,6 +4376,7 @@ def _testCmsgTrunc2Int(self): self.createAndSendFDs(1) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen0Minus1(self): self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), socket.CMSG_LEN(0) - 1)) @@ -4408,6 +4414,7 @@ def checkTruncatedArray(self, ancbuf, maxdata, mindata=0): self.checkFDs(fds) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen0(self): self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0), maxdata=0) @@ -4416,6 +4423,7 @@ def _testCmsgTruncLen0(self): self.createAndSendFDs(1) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen0Plus1(self): self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0) + 1, maxdata=1) @@ -4424,6 +4432,7 @@ def _testCmsgTruncLen0Plus1(self): self.createAndSendFDs(2) @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen1(self): self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(SIZEOF_INT), maxdata=SIZEOF_INT) @@ -4434,6 +4443,7 @@ def _testCmsgTruncLen1(self): @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testCmsgTruncLen2Minus1(self): self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(2 * SIZEOF_INT) - 1, maxdata=(2 * SIZEOF_INT) - 1) @@ -4706,6 +4716,7 @@ def _testSingleCmsgTrunc0(self): # (but still too small) buffer sizes. @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSingleCmsgTrunc1(self): self.checkHopLimitTruncatedHeader(ancbufsize=1) @@ -4715,6 +4726,7 @@ def _testSingleCmsgTrunc1(self): self.sendToServer(MSG) @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSingleCmsgTrunc2Int(self): self.checkHopLimitTruncatedHeader(ancbufsize=2 * SIZEOF_INT) @@ -4724,6 +4736,7 @@ def _testSingleCmsgTrunc2Int(self): self.sendToServer(MSG) @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSingleCmsgTruncLen0Minus1(self): self.checkHopLimitTruncatedHeader(ancbufsize=socket.CMSG_LEN(0) - 1) @@ -4733,6 +4746,7 @@ def _testSingleCmsgTruncLen0Minus1(self): self.sendToServer(MSG) @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSingleCmsgTruncInData(self): # Test truncation of a control message inside its associated # data. The message may be returned with its data truncated, @@ -4805,6 +4819,7 @@ def _testSecondCmsgTrunc0(self): @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT", "IPV6_RECVTCLASS", "IPV6_TCLASS") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSecondCmsgTrunc1(self): self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT) + 1) @@ -4815,6 +4830,7 @@ def _testSecondCmsgTrunc1(self): @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT", "IPV6_RECVTCLASS", "IPV6_TCLASS") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSecondCmsgTrunc2Int(self): self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT) + 2 * SIZEOF_INT) @@ -4826,6 +4842,7 @@ def _testSecondCmsgTrunc2Int(self): @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT", "IPV6_RECVTCLASS", "IPV6_TCLASS") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSecondCmsgTruncLen0Minus1(self): self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT) + socket.CMSG_LEN(0) - 1) @@ -4837,6 +4854,7 @@ def _testSecondCmsgTruncLen0Minus1(self): @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT", "IPV6_RECVTCLASS", "IPV6_TCLASS") + @unittest.skipIf(CMSG_TRUNC_RAISES_EMSGSIZE, "skipping, see gh-154240") def testSecondCmsgTruncInData(self): # Test truncation of the second of two control messages inside # its associated data. diff --git a/Misc/NEWS.d/next/Library/2026-07-20-18-30-00.gh-issue-154258.mmapresize.rst b/Misc/NEWS.d/next/Library/2026-07-20-18-30-00.gh-issue-154258.mmapresize.rst new file mode 100644 index 000000000000000..4c33336e0bbdcad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-20-18-30-00.gh-issue-154258.mmapresize.rst @@ -0,0 +1,3 @@ +Fix a crash in :meth:`mmap.mmap.resize` on NetBSD when growing a shared +anonymous mapping. :meth:`!resize` now raises :exc:`ValueError` in this +case, as it already did on Linux. diff --git a/Misc/NEWS.d/next/Tests/2026-07-19-20-15-00.gh-issue-154167.sigint.rst b/Misc/NEWS.d/next/Tests/2026-07-19-20-15-00.gh-issue-154167.sigint.rst new file mode 100644 index 000000000000000..b2620f4a0bee54c --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-07-19-20-15-00.gh-issue-154167.sigint.rst @@ -0,0 +1,3 @@ +The test runner (regrtest) now restores the default SIGINT handler if it +was inherited as ignored, so the test suite no longer hangs when run as +a shell background job. diff --git a/Misc/NEWS.d/next/Windows/2026-06-30-16-40-00.gh-issue-152433.VaeEwR.rst b/Misc/NEWS.d/next/Windows/2026-06-30-16-40-00.gh-issue-152433.VaeEwR.rst new file mode 100644 index 000000000000000..00f89ffcbc1c29a --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-06-30-16-40-00.gh-issue-152433.VaeEwR.rst @@ -0,0 +1 @@ +``_winapi``: implement ``GetVersion()`` UWP alternative. diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 535784adedb24d8..a649d84a7925a04 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1739,7 +1739,19 @@ _winapi_GetVersion_impl(PyObject *module) #pragma warning(disable:4996) { +#ifdef MS_WINDOWS_DESKTOP return GetVersion(); +#else + OSVERSIONINFOW version_info; + ZeroMemory(&version_info, sizeof(version_info)); + version_info.dwOSVersionInfoSize = sizeof(version_info); + if (GetVersionExW(&version_info)) { + return version_info.dwMinorVersion | + (version_info.dwMajorVersion << 8) | + (version_info.dwBuildNumber << 16); + } + return 0; +#endif } #pragma warning(pop) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index d55ab3d4d56edb0..e521e95d4ded73f 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -969,10 +969,13 @@ mmap_mmap_resize_impl(mmap_object *self, Py_ssize_t new_size) #ifdef UNIX void *newmap; -#ifdef __linux__ +#if defined(__linux__) || defined(__NetBSD__) + // Linux mremap() refuses to grow a shared anonymous mapping, and + // NetBSD mremap() returns a mapping whose grown region is not backed, + // so accessing it crashes. Reject it here in both cases. if (self->fd == -1 && !(self->flags & MAP_PRIVATE) && new_size > self->size) { PyErr_Format(PyExc_ValueError, - "mmap: can't expand a shared anonymous mapping on Linux"); + "mmap: can't expand a shared anonymous mapping"); return NULL; } #endif