FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-124872: Back up exception before calling PyContext_WatchCallback by rhansen · Pull Request #124741 · python/cpython · GitHub

Repository navigation

Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension .c  (1) .h  (1) .py  (1) .rst  (1) All 4 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
Next Next commit
gh-124872: Back up exception before calling PyContext_WatchCallback
I believe that the value of a simpler API (and defense against poorly
written callbacks) outweighs the cost of backing up and restoring the
thread's exception state.
  • Loading branch information
rhansen committed Oct 12, 2024
commit c5789a95cf273dcc699fa6e58045022d41982f38
9 changes: 3 additions & 6 deletions Doc/c-api/contextvars.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,13 @@ Context object management functions:
Context object watcher callback function. The object passed to the callback
is event-specific; see :c:type:`PyContextEvent` for details.

Any pending exception is cleared before the callback is called and restored
Comment thread
rhansen marked this conversation as resolved.
Resolved
after the callback returns.

If the callback returns with an exception set, it must return ``-1``; this
exception will be printed as an unraisable exception using
:c:func:`PyErr_FormatUnraisable`. Otherwise it should return ``0``.

There may already be a pending exception set on entry to the callback. In
this case, the callback should return ``0`` with the same exception still
set. This means the callback may not call any other API that can set an
exception unless it saves and clears the exception state first, and restores
it before returning.

Comment thread
rhansen marked this conversation as resolved.
Resolved
.. versionadded:: 3.14


Expand Down
3 changes: 3 additions & 0 deletions Include/cpython/context.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ typedef enum {
* Context object watcher callback function. The object passed to the callback
* is event-specific; see PyContextEvent for details.
*
* Any pending exception is cleared before the callback is called and restored
* after the callback returns.
*
* if the callback returns with an exception set, it must return -1. Otherwise
* it should return 0
*/
Expand Down
10 changes: 10 additions & 0 deletions Lib/test/test_capi/test_watchers.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,16 @@ def _in_context(stack):
ctx.run(_in_context, stack)
self.assertEqual(str(cm.unraisable.exc_value), "boom!")

def test_exception_save(self):
with self.context_watcher(2):
with catch_unraisable_exception() as cm:
def _in_context():
raise RuntimeError("test")

with self.assertRaisesRegex(RuntimeError, "test"):
contextvars.copy_context().run(_in_context)
self.assertEqual(str(cm.unraisable.exc_value), "boom!")

def test_clear_out_of_range_watcher_id(self):
with self.assertRaisesRegex(ValueError, r"Invalid context watcher ID -1"):
_testcapi.clear_context_watcher(-1)
Expand Down
2 changes: 2 additions & 0 deletions Python/context.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,13 @@ notify_context_watchers(PyThreadState *ts, PyContextEvent event, PyObject *ctx)
if (bits & 1) {
PyContext_WatchCallback cb = interp->context_watchers[i];
assert(cb != NULL);
PyObject *exc = _PyErr_GetRaisedException(ts);
if (cb(event, ctx) < 0) {
PyErr_FormatUnraisable(
"Exception ignored in %s watcher callback for %R",
context_event_name(event), ctx);
}
_PyErr_SetRaisedException(ts, exc);
}
i++;
bits >>= 1;
Expand Down

Back | FazBrowse Home | New Git URL