Skip to content

Commit 0902afb

Browse files
authored
[3.12] GH-106895: Raise a ValueError when attempting to disable events that cannot be disabled. (GH-107337) (GH-107351)
1 parent 3b1a4c1 commit 0902afb

File tree

8 files changed

+207
-144
lines changed

8 files changed

+207
-144
lines changed

Include/internal/pycore_instruments.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ extern "C" {
2828
#define PY_MONITORING_EVENT_BRANCH 8
2929
#define PY_MONITORING_EVENT_STOP_ITERATION 9
3030

31-
#define PY_MONITORING_INSTRUMENTED_EVENTS 10
31+
#define PY_MONITORING_IS_INSTRUMENTED_EVENT(ev) \
32+
((ev) <= PY_MONITORING_EVENT_STOP_ITERATION)
3233

3334
/* Other events, mainly exceptions */
3435

Lib/test/test_monitoring.py

+51-1
Original file line numberDiff line numberDiff line change
@@ -136,20 +136,27 @@ def test_c_return_count(self):
136136

137137
E = sys.monitoring.events
138138

139-
SIMPLE_EVENTS = [
139+
INSTRUMENTED_EVENTS = [
140140
(E.PY_START, "start"),
141141
(E.PY_RESUME, "resume"),
142142
(E.PY_RETURN, "return"),
143143
(E.PY_YIELD, "yield"),
144144
(E.JUMP, "jump"),
145145
(E.BRANCH, "branch"),
146+
]
147+
148+
EXCEPT_EVENTS = [
146149
(E.RAISE, "raise"),
147150
(E.PY_UNWIND, "unwind"),
148151
(E.EXCEPTION_HANDLED, "exception_handled"),
152+
]
153+
154+
SIMPLE_EVENTS = INSTRUMENTED_EVENTS + EXCEPT_EVENTS + [
149155
(E.C_RAISE, "c_raise"),
150156
(E.C_RETURN, "c_return"),
151157
]
152158

159+
153160
SIMPLE_EVENT_SET = functools.reduce(operator.or_, [ev for (ev, _) in SIMPLE_EVENTS], 0) | E.CALL
154161

155162

@@ -618,6 +625,49 @@ def func2():
618625

619626
self.check_lines(func2, [1,2,3,4,5,6])
620627

628+
class TestDisable(MonitoringTestBase, unittest.TestCase):
629+
630+
def gen(self, cond):
631+
for i in range(10):
632+
if cond:
633+
yield 1
634+
else:
635+
yield 2
636+
637+
def raise_handle_reraise(self):
638+
try:
639+
1/0
640+
except:
641+
raise
642+
643+
def test_disable_legal_events(self):
644+
for event, name in INSTRUMENTED_EVENTS:
645+
try:
646+
counter = CounterWithDisable()
647+
counter.disable = True
648+
sys.monitoring.register_callback(TEST_TOOL, event, counter)
649+
sys.monitoring.set_events(TEST_TOOL, event)
650+
for _ in self.gen(1):
651+
pass
652+
self.assertLess(counter.count, 4)
653+
finally:
654+
sys.monitoring.set_events(TEST_TOOL, 0)
655+
sys.monitoring.register_callback(TEST_TOOL, event, None)
656+
657+
658+
def test_disable_illegal_events(self):
659+
for event, name in EXCEPT_EVENTS:
660+
try:
661+
counter = CounterWithDisable()
662+
counter.disable = True
663+
sys.monitoring.register_callback(TEST_TOOL, event, counter)
664+
sys.monitoring.set_events(TEST_TOOL, event)
665+
with self.assertRaises(ValueError):
666+
self.raise_handle_reraise()
667+
finally:
668+
sys.monitoring.set_events(TEST_TOOL, 0)
669+
sys.monitoring.register_callback(TEST_TOOL, event, None)
670+
621671

622672
class ExceptionRecorder:
623673

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Raise a ``ValueError`` when a monitoring callback funtion returns
2+
``DISABLE`` for events that cannot be disabled locally.

Objects/classobject.c

+2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ method_vectorcall(PyObject *method, PyObject *const *args,
4848
PyObject *self = PyMethod_GET_SELF(method);
4949
PyObject *func = PyMethod_GET_FUNCTION(method);
5050
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
51+
assert(nargs == 0 || args[nargs-1]);
5152

5253
PyObject *result;
5354
if (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET) {
@@ -56,6 +57,7 @@ method_vectorcall(PyObject *method, PyObject *const *args,
5657
nargs += 1;
5758
PyObject *tmp = newargs[0];
5859
newargs[0] = self;
60+
assert(newargs[nargs-1]);
5961
result = _PyObject_VectorcallTstate(tstate, func, newargs,
6062
nargs, kwnames);
6163
newargs[0] = tmp;

Python/bytecodes.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -2476,7 +2476,12 @@ dummy_func(
24762476
assert(val && PyExceptionInstance_Check(val));
24772477
exc = PyExceptionInstance_Class(val);
24782478
tb = PyException_GetTraceback(val);
2479-
Py_XDECREF(tb);
2479+
if (tb == NULL) {
2480+
tb = Py_None;
2481+
}
2482+
else {
2483+
Py_DECREF(tb);
2484+
}
24802485
assert(PyLong_Check(lasti));
24812486
(void)lasti; // Shut up compiler warning if asserts are off
24822487
PyObject *stack[4] = {NULL, exc, val, tb};

Python/ceval.c

+8-5
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ static int monitor_stop_iteration(PyThreadState *tstate,
194194
static void monitor_unwind(PyThreadState *tstate,
195195
_PyInterpreterFrame *frame,
196196
_Py_CODEUNIT *instr);
197-
static void monitor_handled(PyThreadState *tstate,
197+
static int monitor_handled(PyThreadState *tstate,
198198
_PyInterpreterFrame *frame,
199199
_Py_CODEUNIT *instr, PyObject *exc);
200200
static void monitor_throw(PyThreadState *tstate,
@@ -969,7 +969,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
969969
PyObject *exc = _PyErr_GetRaisedException(tstate);
970970
PUSH(exc);
971971
JUMPTO(handler);
972-
monitor_handled(tstate, frame, next_instr, exc);
972+
if (monitor_handled(tstate, frame, next_instr, exc) < 0) {
973+
goto exception_unwind;
974+
}
973975
/* Resume normal execution */
974976
DISPATCH();
975977
}
@@ -2007,6 +2009,7 @@ do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame,
20072009
PyErr_SetRaisedException(exc);
20082010
}
20092011
else {
2012+
assert(PyErr_Occurred());
20102013
Py_DECREF(exc);
20112014
}
20122015
return err;
@@ -2071,15 +2074,15 @@ monitor_unwind(PyThreadState *tstate,
20712074
}
20722075

20732076

2074-
static void
2077+
static int
20752078
monitor_handled(PyThreadState *tstate,
20762079
_PyInterpreterFrame *frame,
20772080
_Py_CODEUNIT *instr, PyObject *exc)
20782081
{
20792082
if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_EXCEPTION_HANDLED)) {
2080-
return;
2083+
return 0;
20812084
}
2082-
_Py_call_instrumentation_arg(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED, frame, instr, exc);
2085+
return _Py_call_instrumentation_arg(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED, frame, instr, exc);
20832086
}
20842087

20852088
static void

0 commit comments

Comments
 (0)