Compare commits

...

6 commits

Author SHA1 Message Date
Frost Ming
d86ad870cc
gh-140251: colorize import statement formatting in asyncio console (#140252) 2025-10-18 20:05:24 +05:30
Kumar Aditya
58c44c2bf2
gh-140067: Fix memory leak in sub-interpreter creation (#140111) (#140261)
Fix memory leak in sub-interpreter creation caused by overwriting of the previously used `_malloced` field. Now the pointer is stored in the first word of the memory block to avoid it being overwritten accidentally. 

Co-authored-by: Kumar Aditya <kumaraditya@python.org>
2025-10-18 16:36:58 +05:30
Shamil
c8729c9909
gh-140257: fix data race on eval_breaker during finalization (#140265) 2025-10-18 16:31:53 +05:30
Serhiy Storchaka
78e1d65a4d
gh-140241: Fix documentation for the registry parameter of warnings.warn_explicit() (GH-140242)
Co-authored-by: Petr Viktorin <encukou@gmail.com>
2025-10-18 13:55:26 +03:00
Serhiy Storchaka
936de256a9
Move the NEWS entry for gh-140272 to the correct place (GH-140290) 2025-10-18 10:54:40 +00:00
Shamil
f937468e7c
gh-140272: Fix memory leak in _gdbm.gdbm.clear() (GH-140274) 2025-10-18 09:27:58 +00:00
10 changed files with 36 additions and 20 deletions

View file

@ -480,14 +480,21 @@ Available Functions
.. function:: warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)
This is a low-level interface to the functionality of :func:`warn`, passing in
explicitly the message, category, filename and line number, and optionally the
module name and the registry (which should be the ``__warningregistry__``
dictionary of the module). The module name defaults to the filename with
``.py`` stripped; if no registry is passed, the warning is never suppressed.
explicitly the message, category, filename and line number, and optionally
other arguments.
*message* must be a string and *category* a subclass of :exc:`Warning` or
*message* may be a :exc:`Warning` instance, in which case *category* will be
ignored.
*module*, if supplied, should be the module name.
If no module is passed, the filename with ``.py`` stripped is used.
*registry*, if supplied, should be the ``__warningregistry__`` dictionary
of the module.
If no registry is passed, each warning is treated as the first occurrence,
that is, filter actions ``"default"``, ``"module"`` and ``"once"`` are
handled as ``"always"``.
*module_globals*, if supplied, should be the global namespace in use by the code
for which the warning is issued. (This argument is used to support displaying
source for modules found in zipfiles or other non-filesystem import

View file

@ -769,12 +769,6 @@ struct _is {
* and should be placed at the beginning. */
struct _ceval_state ceval;
/* This structure is carefully allocated so that it's correctly aligned
* to avoid undefined behaviors during LOAD and STORE. The '_malloced'
* field stores the allocated pointer address that will later be freed.
*/
void *_malloced;
PyInterpreterState *next;
int64_t id;

View file

@ -107,7 +107,10 @@ def run(self):
if CAN_USE_PYREPL:
theme = get_theme().syntax
ps1 = f"{theme.prompt}{ps1}{theme.reset}"
console.write(f"{ps1}import asyncio\n")
import_line = f'{theme.keyword}import{theme.reset} asyncio'
else:
import_line = "import asyncio"
console.write(f"{ps1}{import_line}\n")
if CAN_USE_PYREPL:
from _pyrepl.simple_interact import (

View file

@ -1776,6 +1776,7 @@ def task():
self.assertEqual(os.read(r_interp, 1), DONE)
@cpython_only
@support.skip_if_sanitizer(thread=True, memory=True)
def test_daemon_threads_fatal_error(self):
import_module("_testcapi")
subinterp_code = f"""if 1:

View file

@ -0,0 +1 @@
Fix memory leak in sub-interpreter creation.

View file

@ -0,0 +1,2 @@
Fix data race between interpreter_clear() and take_gil() on eval_breaker
during finalization with daemon threads.

View file

@ -0,0 +1 @@
Colorize the default import statement ``import asyncio`` in asyncio REPL.

View file

@ -0,0 +1 @@
Fix memory leak in the :meth:`!clear` method of the :mod:`dbm.gnu` database.

View file

@ -673,8 +673,10 @@ _gdbm_gdbm_clear_impl(gdbmobject *self, PyTypeObject *cls)
}
if (gdbm_delete(self->di_dbm, key) < 0) {
PyErr_SetString(state->gdbm_error, "cannot delete item from database");
free(key.dptr);
return NULL;
}
free(key.dptr);
}
Py_RETURN_NONE;
}

View file

@ -457,16 +457,19 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
static PyInterpreterState *
alloc_interpreter(void)
{
// Aligned allocation for PyInterpreterState.
// the first word of the memory block is used to store
// the original pointer to be used later to free the memory.
size_t alignment = _Alignof(PyInterpreterState);
size_t allocsize = sizeof(PyInterpreterState) + alignment - 1;
size_t allocsize = sizeof(PyInterpreterState) + sizeof(void *) + alignment - 1;
void *mem = PyMem_RawCalloc(1, allocsize);
if (mem == NULL) {
return NULL;
}
PyInterpreterState *interp = _Py_ALIGN_UP(mem, alignment);
assert(_Py_IS_ALIGNED(interp, alignment));
interp->_malloced = mem;
return interp;
void *ptr = _Py_ALIGN_UP((char *)mem + sizeof(void *), alignment);
((void **)ptr)[-1] = mem;
assert(_Py_IS_ALIGNED(ptr, alignment));
return ptr;
}
static void
@ -481,7 +484,7 @@ free_interpreter(PyInterpreterState *interp)
interp->obmalloc = NULL;
}
assert(_Py_IS_ALIGNED(interp, _Alignof(PyInterpreterState)));
PyMem_RawFree(interp->_malloced);
PyMem_RawFree(((void **)interp)[-1]);
}
}
@ -763,10 +766,11 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
Py_CLEAR(interp->audit_hooks);
// At this time, all the threads should be cleared so we don't need atomic
// operations for instrumentation_version or eval_breaker.
// gh-140257: Threads have already been cleared, but daemon threads may
// still access eval_breaker atomically via take_gil() right before they
// hang. Use an atomic store to prevent data races during finalization.
interp->ceval.instrumentation_version = 0;
tstate->eval_breaker = 0;
_Py_atomic_store_uintptr(&tstate->eval_breaker, 0);
for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) {
interp->monitors.tools[i] = 0;