mirror of
https://github.com/python/cpython.git
synced 2025-10-19 07:53:46 +00:00
Compare commits
5 commits
f59236b746
...
1d11627ba5
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1d11627ba5 | ||
![]() |
3ca7ea1f8f | ||
![]() |
c70f409da0 | ||
![]() |
b2d3957511 | ||
![]() |
128f48fd2d |
8 changed files with 32 additions and 17 deletions
|
@ -476,14 +476,21 @@ Available Functions
|
||||||
.. function:: warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)
|
.. 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
|
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
|
explicitly the message, category, filename and line number, and optionally
|
||||||
module name and the registry (which should be the ``__warningregistry__``
|
other arguments.
|
||||||
dictionary of the module). The module name defaults to the filename with
|
|
||||||
``.py`` stripped; if no registry is passed, the warning is never suppressed.
|
|
||||||
*message* must be a string and *category* a subclass of :exc:`Warning` or
|
*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
|
*message* may be a :exc:`Warning` instance, in which case *category* will be
|
||||||
ignored.
|
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
|
*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
|
for which the warning is issued. (This argument is used to support displaying
|
||||||
source for modules found in zipfiles or other non-filesystem import
|
source for modules found in zipfiles or other non-filesystem import
|
||||||
|
|
|
@ -768,10 +768,7 @@ struct _is {
|
||||||
* and should be placed at the beginning. */
|
* and should be placed at the beginning. */
|
||||||
struct _ceval_state ceval;
|
struct _ceval_state ceval;
|
||||||
|
|
||||||
/* This structure is carefully allocated so that it's correctly aligned
|
// unused, kept for ABI compatibility
|
||||||
* to avoid undefined behaviors during LOAD and STORE. The '_malloced'
|
|
||||||
* field stores the allocated pointer address that will later be freed.
|
|
||||||
*/
|
|
||||||
void *_malloced;
|
void *_malloced;
|
||||||
|
|
||||||
PyInterpreterState *next;
|
PyInterpreterState *next;
|
||||||
|
|
|
@ -1727,6 +1727,7 @@ def task():
|
||||||
self.assertEqual(os.read(r_interp, 1), DONE)
|
self.assertEqual(os.read(r_interp, 1), DONE)
|
||||||
|
|
||||||
@cpython_only
|
@cpython_only
|
||||||
|
@support.skip_if_sanitizer(thread=True, memory=True)
|
||||||
def test_daemon_threads_fatal_error(self):
|
def test_daemon_threads_fatal_error(self):
|
||||||
import_module("_testcapi")
|
import_module("_testcapi")
|
||||||
subinterp_code = f"""if 1:
|
subinterp_code = f"""if 1:
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fix memory leak in sub-interpreter creation.
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix data race between interpreter_clear() and take_gil() on eval_breaker
|
||||||
|
during finalization with daemon threads.
|
|
@ -0,0 +1 @@
|
||||||
|
Fix memory leak in the :meth:`!clear` method of the :mod:`dbm.gnu` database.
|
|
@ -678,8 +678,10 @@ _gdbm_gdbm_clear_impl(gdbmobject *self, PyTypeObject *cls)
|
||||||
}
|
}
|
||||||
if (gdbm_delete(self->di_dbm, key) < 0) {
|
if (gdbm_delete(self->di_dbm, key) < 0) {
|
||||||
PyErr_SetString(state->gdbm_error, "cannot delete item from database");
|
PyErr_SetString(state->gdbm_error, "cannot delete item from database");
|
||||||
|
free(key.dptr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
free(key.dptr);
|
||||||
}
|
}
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -565,16 +565,19 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
|
||||||
static PyInterpreterState *
|
static PyInterpreterState *
|
||||||
alloc_interpreter(void)
|
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 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);
|
void *mem = PyMem_RawCalloc(1, allocsize);
|
||||||
if (mem == NULL) {
|
if (mem == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyInterpreterState *interp = _Py_ALIGN_UP(mem, alignment);
|
void *ptr = _Py_ALIGN_UP((char *)mem + sizeof(void *), alignment);
|
||||||
assert(_Py_IS_ALIGNED(interp, alignment));
|
((void **)ptr)[-1] = mem;
|
||||||
interp->_malloced = mem;
|
assert(_Py_IS_ALIGNED(ptr, alignment));
|
||||||
return interp;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -589,7 +592,7 @@ free_interpreter(PyInterpreterState *interp)
|
||||||
interp->obmalloc = NULL;
|
interp->obmalloc = NULL;
|
||||||
}
|
}
|
||||||
assert(_Py_IS_ALIGNED(interp, _Alignof(PyInterpreterState)));
|
assert(_Py_IS_ALIGNED(interp, _Alignof(PyInterpreterState)));
|
||||||
PyMem_RawFree(interp->_malloced);
|
PyMem_RawFree(((void **)interp)[-1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -860,10 +863,11 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
|
||||||
|
|
||||||
Py_CLEAR(interp->audit_hooks);
|
Py_CLEAR(interp->audit_hooks);
|
||||||
|
|
||||||
// At this time, all the threads should be cleared so we don't need atomic
|
// gh-140257: Threads have already been cleared, but daemon threads may
|
||||||
// operations for instrumentation_version or eval_breaker.
|
// 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;
|
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++) {
|
for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) {
|
||||||
interp->monitors.tools[i] = 0;
|
interp->monitors.tools[i] = 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue