Skip to content

Commit 212948c

Browse files
committed
fixup! gh-119333: Back up exception before calling PyContext_WatchCallback
I changed my mind about where to back up and restore the exception. Instead of backing up and restoring once outside the loop over the registered callbacks, the exception is backed up and restored each time a callback is called. This avoids concerns about what happens if a callback raises an exception but returns non-negative. This is also expected to be more efficient, not less, because the common case is no watchers at all, in which case there is no backup/restore overhead. The second most common case is one watcher, which is no less efficient than before. The only time this is more expensive is when there are two or more watchers, in which case the overhead of the watcher callbacks probably dwarfs the overhead of the extra backups anyways.
1 parent ffa8cc8 commit 212948c

File tree

1 file changed

+2
-2
lines changed

1 file changed

+2
-2
lines changed

Python/context.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,23 +119,23 @@ static void notify_context_watchers(PyContextEvent event, PyContext *ctx, PyThre
119119
assert(interp->_initialized);
120120
uint8_t bits = interp->active_context_watchers;
121121
int i = 0;
122-
PyObject *exc = _PyErr_GetRaisedException(ts);
123122
while (bits) {
124123
assert(i < CONTEXT_MAX_WATCHERS);
125124
if (bits & 1) {
126125
PyContext_WatchCallback cb = interp->context_watchers[i];
127126
assert(cb != NULL);
127+
PyObject *exc = _PyErr_GetRaisedException(ts);
128128
cb(event, ctx);
129129
if (_PyErr_Occurred(ts) != NULL) {
130130
PyErr_FormatUnraisable(
131131
"Exception ignored in %s watcher callback for %R",
132132
context_event_name(event), ctx);
133133
}
134+
_PyErr_SetRaisedException(ts, exc);
134135
}
135136
i++;
136137
bits >>= 1;
137138
}
138-
_PyErr_SetRaisedException(ts, exc);
139139
}
140140

141141

0 commit comments

Comments
 (0)