Skip to content

bpo-36829: Add a -X option to abort in PyErr_WriteUnraisable() #13175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Doc/c-api/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ Printing and clearing
in which the unraisable exception occurred. If possible,
the repr of *obj* will be printed in the warning message.

.. versionchanged:: 3.8
The :option:`-X` ``abortunraisable`` command-line option causes this
function to abort the current process.


Raising exceptions
==================
Expand Down
8 changes: 6 additions & 2 deletions Doc/using/cmdline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@ Miscellaneous options
* ``-X pycache_prefix=PATH`` enables writing ``.pyc`` files to a parallel
tree rooted at the given directory instead of to the code tree. See also
:envvar:`PYTHONPYCACHEPREFIX`.
* ``-X abortunraisable`` causes the :c:func:`PyErr_WriteUnraisable`
function to abort the current process. This is useful for debugging
purposes.

It also allows passing arbitrary values and retrieving them through the
:data:`sys._xoptions` dictionary.
Expand All @@ -466,8 +469,9 @@ Miscellaneous options
The ``-X importtime``, ``-X dev`` and ``-X utf8`` options.

.. versionadded:: 3.8
The ``-X pycache_prefix`` option. The ``-X dev`` option now logs
``close()`` exceptions in :class:`io.IOBase` destructor.
The ``-X pycache_prefix`` and ``-X abortunraisable`` options. The
``-X dev`` option now logs ``close()`` exceptions in the
:class:`io.IOBase` destructor.


Options you shouldn't use
Expand Down
3 changes: 3 additions & 0 deletions Doc/whatsnew/3.8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ Other Language Changes
and Windows use this to properly terminate scripts in interactive sessions.
(Contributed by Google via Gregory P. Smith in :issue:`1054041`.)

* The new :option:`-X` ``abortunraisable`` option causes the
:c:func:`PyErr_WriteUnraisable` C API function to abort the current process.
(Contributed by Zackery Spytz in :issue:`36829`.)

New Modules
===========
Expand Down
1 change: 1 addition & 0 deletions Include/cpython/coreconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ typedef struct {
int import_time; /* PYTHONPROFILEIMPORTTIME, -X importtime */
int show_ref_count; /* -X showrefcount */
int show_alloc_count; /* -X showalloccount */
int abort_unraisable; /* -X abortunraisable */
int dump_refs; /* PYTHONDUMPREFS */
int malloc_stats; /* PYTHONMALLOCSTATS */

Expand Down
2 changes: 1 addition & 1 deletion Lib/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ def _args_from_interpreter_flags():
if dev_mode:
args.extend(('-X', 'dev'))
for opt in ('faulthandler', 'tracemalloc', 'importtime',
'showalloccount', 'showrefcount', 'utf8'):
'showalloccount', 'showrefcount', 'utf8', 'abortunraisable'):
if opt in xoptions:
value = xoptions[opt]
if value is True:
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
'import_time': 0,
'show_ref_count': 0,
'show_alloc_count': 0,
'abort_unraisable': 0,
'dump_refs': 0,
'malloc_stats': 0,

Expand Down Expand Up @@ -554,6 +555,7 @@ def test_init_from_config(self):
'import_time': 1,
'show_ref_count': 1,
'show_alloc_count': 1,
'abort_unraisable': 1,
'malloc_stats': 1,

'stdio_encoding': 'iso8859-1',
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ def test_args_from_interpreter_flags(self):
['-X', 'importtime'],
['-X', 'showalloccount'],
['-X', 'showrefcount'],
['-X', 'abortunraisable'],
['-X', 'tracemalloc'],
['-X', 'tracemalloc=3'],
):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add a -X command-line option to abort the current process if
:c:func:`PyErr_WriteUnraisable` is called.
1 change: 1 addition & 0 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ static int test_init_from_config(void)

config.show_ref_count = 1;
config.show_alloc_count = 1;
config.abort_unraisable = 1;
/* FIXME: test dump_refs: bpo-34223 */

putenv("PYTHONMALLOCSTATS=0");
Expand Down
5 changes: 5 additions & 0 deletions Python/coreconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
COPY_ATTR(import_time);
COPY_ATTR(show_ref_count);
COPY_ATTR(show_alloc_count);
COPY_ATTR(abort_unraisable);
COPY_ATTR(dump_refs);
COPY_ATTR(malloc_stats);

Expand Down Expand Up @@ -721,6 +722,7 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config)
SET_ITEM_INT(import_time);
SET_ITEM_INT(show_ref_count);
SET_ITEM_INT(show_alloc_count);
SET_ITEM_INT(abort_unraisable);
SET_ITEM_INT(dump_refs);
SET_ITEM_INT(malloc_stats);
SET_ITEM_WSTR(filesystem_encoding);
Expand Down Expand Up @@ -1507,6 +1509,9 @@ config_read(_PyCoreConfig *config, _PyPreCmdline *cmdline)
if (config_get_xoption(config, L"showalloccount")) {
config->show_alloc_count = 1;
}
if (config_get_xoption(config, L"abortunraisable")) {
config->abort_unraisable = 1;
}

err = config_read_complex_options(config);
if (_Py_INIT_FAILED(err)) {
Expand Down
4 changes: 4 additions & 0 deletions Python/errors.c
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,10 @@ PyErr_WriteUnraisable(PyObject *obj)
Py_XDECREF(t);
Py_XDECREF(v);
Py_XDECREF(tb);
PyInterpreterState *interp = _PyInterpreterState_Get();
if (interp->core_config.abort_unraisable) {
Py_FatalError("Unraisable exception");
}
PyErr_Clear(); /* Just in case */
}

Expand Down