Branch data Line data Source code
1 : : #include "parts.h"
2 : :
3 : : #define Py_BUILD_CORE
4 : : #include "pycore_function.h" // FUNC_MAX_WATCHERS
5 : : #include "pycore_code.h" // CODE_MAX_WATCHERS
6 : :
7 : : // Test dict watching
8 : : static PyObject *g_dict_watch_events;
9 : : static int g_dict_watchers_installed;
10 : :
11 : : static int
12 : 0 : dict_watch_callback(PyDict_WatchEvent event,
13 : : PyObject *dict,
14 : : PyObject *key,
15 : : PyObject *new_value)
16 : : {
17 : : PyObject *msg;
18 [ # # # # : 0 : switch (event) {
# # # ]
19 : 0 : case PyDict_EVENT_CLEARED:
20 : 0 : msg = PyUnicode_FromString("clear");
21 : 0 : break;
22 : 0 : case PyDict_EVENT_DEALLOCATED:
23 : 0 : msg = PyUnicode_FromString("dealloc");
24 : 0 : break;
25 : 0 : case PyDict_EVENT_CLONED:
26 : 0 : msg = PyUnicode_FromString("clone");
27 : 0 : break;
28 : 0 : case PyDict_EVENT_ADDED:
29 : 0 : msg = PyUnicode_FromFormat("new:%S:%S", key, new_value);
30 : 0 : break;
31 : 0 : case PyDict_EVENT_MODIFIED:
32 : 0 : msg = PyUnicode_FromFormat("mod:%S:%S", key, new_value);
33 : 0 : break;
34 : 0 : case PyDict_EVENT_DELETED:
35 : 0 : msg = PyUnicode_FromFormat("del:%S", key);
36 : 0 : break;
37 : 0 : default:
38 : 0 : msg = PyUnicode_FromString("unknown");
39 : : }
40 [ # # ]: 0 : if (msg == NULL) {
41 : 0 : return -1;
42 : : }
43 [ # # ]: 0 : assert(PyList_Check(g_dict_watch_events));
44 [ # # ]: 0 : if (PyList_Append(g_dict_watch_events, msg) < 0) {
45 : 0 : Py_DECREF(msg);
46 : 0 : return -1;
47 : : }
48 : 0 : Py_DECREF(msg);
49 : 0 : return 0;
50 : : }
51 : :
52 : : static int
53 : 0 : dict_watch_callback_second(PyDict_WatchEvent event,
54 : : PyObject *dict,
55 : : PyObject *key,
56 : : PyObject *new_value)
57 : : {
58 : 0 : PyObject *msg = PyUnicode_FromString("second");
59 [ # # ]: 0 : if (msg == NULL) {
60 : 0 : return -1;
61 : : }
62 : 0 : int rc = PyList_Append(g_dict_watch_events, msg);
63 : 0 : Py_DECREF(msg);
64 [ # # ]: 0 : if (rc < 0) {
65 : 0 : return -1;
66 : : }
67 : 0 : return 0;
68 : : }
69 : :
70 : : static int
71 : 0 : dict_watch_callback_error(PyDict_WatchEvent event,
72 : : PyObject *dict,
73 : : PyObject *key,
74 : : PyObject *new_value)
75 : : {
76 : 0 : PyErr_SetString(PyExc_RuntimeError, "boom!");
77 : 0 : return -1;
78 : : }
79 : :
80 : : static PyObject *
81 : 0 : add_dict_watcher(PyObject *self, PyObject *kind)
82 : : {
83 : : int watcher_id;
84 [ # # ]: 0 : assert(PyLong_Check(kind));
85 : 0 : long kind_l = PyLong_AsLong(kind);
86 [ # # ]: 0 : if (kind_l == 2) {
87 : 0 : watcher_id = PyDict_AddWatcher(dict_watch_callback_second);
88 : : }
89 [ # # ]: 0 : else if (kind_l == 1) {
90 : 0 : watcher_id = PyDict_AddWatcher(dict_watch_callback_error);
91 : : }
92 : : else {
93 : 0 : watcher_id = PyDict_AddWatcher(dict_watch_callback);
94 : : }
95 [ # # ]: 0 : if (watcher_id < 0) {
96 : 0 : return NULL;
97 : : }
98 [ # # ]: 0 : if (!g_dict_watchers_installed) {
99 [ # # ]: 0 : assert(!g_dict_watch_events);
100 [ # # ]: 0 : if (!(g_dict_watch_events = PyList_New(0))) {
101 : 0 : return NULL;
102 : : }
103 : : }
104 : 0 : g_dict_watchers_installed++;
105 : 0 : return PyLong_FromLong(watcher_id);
106 : : }
107 : :
108 : : static PyObject *
109 : 0 : clear_dict_watcher(PyObject *self, PyObject *watcher_id)
110 : : {
111 [ # # ]: 0 : if (PyDict_ClearWatcher(PyLong_AsLong(watcher_id))) {
112 : 0 : return NULL;
113 : : }
114 : 0 : g_dict_watchers_installed--;
115 [ # # ]: 0 : if (!g_dict_watchers_installed) {
116 [ # # ]: 0 : assert(g_dict_watch_events);
117 [ # # ]: 0 : Py_CLEAR(g_dict_watch_events);
118 : : }
119 : 0 : Py_RETURN_NONE;
120 : : }
121 : :
122 : : static PyObject *
123 : 0 : watch_dict(PyObject *self, PyObject *args)
124 : : {
125 : : PyObject *dict;
126 : : int watcher_id;
127 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "iO", &watcher_id, &dict)) {
128 : 0 : return NULL;
129 : : }
130 [ # # ]: 0 : if (PyDict_Watch(watcher_id, dict)) {
131 : 0 : return NULL;
132 : : }
133 : 0 : Py_RETURN_NONE;
134 : : }
135 : :
136 : : static PyObject *
137 : 0 : unwatch_dict(PyObject *self, PyObject *args)
138 : : {
139 : : PyObject *dict;
140 : : int watcher_id;
141 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "iO", &watcher_id, &dict)) {
142 : 0 : return NULL;
143 : : }
144 [ # # ]: 0 : if (PyDict_Unwatch(watcher_id, dict)) {
145 : 0 : return NULL;
146 : : }
147 : 0 : Py_RETURN_NONE;
148 : : }
149 : :
150 : : static PyObject *
151 : 0 : get_dict_watcher_events(PyObject *self, PyObject *Py_UNUSED(args))
152 : : {
153 [ # # ]: 0 : if (!g_dict_watch_events) {
154 : 0 : PyErr_SetString(PyExc_RuntimeError, "no watchers active");
155 : 0 : return NULL;
156 : : }
157 : 0 : return Py_NewRef(g_dict_watch_events);
158 : : }
159 : :
160 : : // Test type watchers
161 : : static PyObject *g_type_modified_events;
162 : : static int g_type_watchers_installed;
163 : :
164 : : static int
165 : 0 : type_modified_callback(PyTypeObject *type)
166 : : {
167 [ # # ]: 0 : assert(PyList_Check(g_type_modified_events));
168 [ # # ]: 0 : if(PyList_Append(g_type_modified_events, (PyObject *)type) < 0) {
169 : 0 : return -1;
170 : : }
171 : 0 : return 0;
172 : : }
173 : :
174 : : static int
175 : 0 : type_modified_callback_wrap(PyTypeObject *type)
176 : : {
177 [ # # ]: 0 : assert(PyList_Check(g_type_modified_events));
178 : 0 : PyObject *list = PyList_New(0);
179 [ # # ]: 0 : if (list == NULL) {
180 : 0 : return -1;
181 : : }
182 [ # # ]: 0 : if (PyList_Append(list, (PyObject *)type) < 0) {
183 : 0 : Py_DECREF(list);
184 : 0 : return -1;
185 : : }
186 [ # # ]: 0 : if (PyList_Append(g_type_modified_events, list) < 0) {
187 : 0 : Py_DECREF(list);
188 : 0 : return -1;
189 : : }
190 : 0 : Py_DECREF(list);
191 : 0 : return 0;
192 : : }
193 : :
194 : : static int
195 : 0 : type_modified_callback_error(PyTypeObject *type)
196 : : {
197 : 0 : PyErr_SetString(PyExc_RuntimeError, "boom!");
198 : 0 : return -1;
199 : : }
200 : :
201 : : static PyObject *
202 : 0 : add_type_watcher(PyObject *self, PyObject *kind)
203 : : {
204 : : int watcher_id;
205 [ # # ]: 0 : assert(PyLong_Check(kind));
206 : 0 : long kind_l = PyLong_AsLong(kind);
207 [ # # ]: 0 : if (kind_l == 2) {
208 : 0 : watcher_id = PyType_AddWatcher(type_modified_callback_wrap);
209 : : }
210 [ # # ]: 0 : else if (kind_l == 1) {
211 : 0 : watcher_id = PyType_AddWatcher(type_modified_callback_error);
212 : : }
213 : : else {
214 : 0 : watcher_id = PyType_AddWatcher(type_modified_callback);
215 : : }
216 [ # # ]: 0 : if (watcher_id < 0) {
217 : 0 : return NULL;
218 : : }
219 [ # # ]: 0 : if (!g_type_watchers_installed) {
220 [ # # ]: 0 : assert(!g_type_modified_events);
221 [ # # ]: 0 : if (!(g_type_modified_events = PyList_New(0))) {
222 : 0 : return NULL;
223 : : }
224 : : }
225 : 0 : g_type_watchers_installed++;
226 : 0 : return PyLong_FromLong(watcher_id);
227 : : }
228 : :
229 : : static PyObject *
230 : 0 : clear_type_watcher(PyObject *self, PyObject *watcher_id)
231 : : {
232 [ # # ]: 0 : if (PyType_ClearWatcher(PyLong_AsLong(watcher_id))) {
233 : 0 : return NULL;
234 : : }
235 : 0 : g_type_watchers_installed--;
236 [ # # ]: 0 : if (!g_type_watchers_installed) {
237 [ # # ]: 0 : assert(g_type_modified_events);
238 [ # # ]: 0 : Py_CLEAR(g_type_modified_events);
239 : : }
240 : 0 : Py_RETURN_NONE;
241 : : }
242 : :
243 : : static PyObject *
244 : 0 : get_type_modified_events(PyObject *self, PyObject *Py_UNUSED(args))
245 : : {
246 [ # # ]: 0 : if (!g_type_modified_events) {
247 : 0 : PyErr_SetString(PyExc_RuntimeError, "no watchers active");
248 : 0 : return NULL;
249 : : }
250 : 0 : return Py_NewRef(g_type_modified_events);
251 : : }
252 : :
253 : : static PyObject *
254 : 0 : watch_type(PyObject *self, PyObject *args)
255 : : {
256 : : PyObject *type;
257 : : int watcher_id;
258 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "iO", &watcher_id, &type)) {
259 : 0 : return NULL;
260 : : }
261 [ # # ]: 0 : if (PyType_Watch(watcher_id, type)) {
262 : 0 : return NULL;
263 : : }
264 : 0 : Py_RETURN_NONE;
265 : : }
266 : :
267 : : static PyObject *
268 : 0 : unwatch_type(PyObject *self, PyObject *args)
269 : : {
270 : : PyObject *type;
271 : : int watcher_id;
272 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "iO", &watcher_id, &type)) {
273 : 0 : return NULL;
274 : : }
275 [ # # ]: 0 : if (PyType_Unwatch(watcher_id, type)) {
276 : 0 : return NULL;
277 : : }
278 : 0 : Py_RETURN_NONE;
279 : : }
280 : :
281 : :
282 : : // Test code object watching
283 : :
284 : : #define NUM_CODE_WATCHERS 2
285 : : static int num_code_object_created_events[NUM_CODE_WATCHERS] = {0, 0};
286 : : static int num_code_object_destroyed_events[NUM_CODE_WATCHERS] = {0, 0};
287 : :
288 : : static int
289 : 0 : handle_code_object_event(int which_watcher, PyCodeEvent event, PyCodeObject *co) {
290 [ # # ]: 0 : if (event == PY_CODE_EVENT_CREATE) {
291 : 0 : num_code_object_created_events[which_watcher]++;
292 : : }
293 [ # # ]: 0 : else if (event == PY_CODE_EVENT_DESTROY) {
294 : 0 : num_code_object_destroyed_events[which_watcher]++;
295 : : }
296 : : else {
297 : 0 : return -1;
298 : : }
299 : 0 : return 0;
300 : : }
301 : :
302 : : static int
303 : 0 : first_code_object_callback(PyCodeEvent event, PyCodeObject *co)
304 : : {
305 : 0 : return handle_code_object_event(0, event, co);
306 : : }
307 : :
308 : : static int
309 : 0 : second_code_object_callback(PyCodeEvent event, PyCodeObject *co)
310 : : {
311 : 0 : return handle_code_object_event(1, event, co);
312 : : }
313 : :
314 : : static int
315 : 0 : noop_code_event_handler(PyCodeEvent event, PyCodeObject *co)
316 : : {
317 : 0 : return 0;
318 : : }
319 : :
320 : : static int
321 : 0 : error_code_event_handler(PyCodeEvent event, PyCodeObject *co)
322 : : {
323 : 0 : PyErr_SetString(PyExc_RuntimeError, "boom!");
324 : 0 : return -1;
325 : : }
326 : :
327 : : static PyObject *
328 : 0 : add_code_watcher(PyObject *self, PyObject *which_watcher)
329 : : {
330 : : int watcher_id;
331 [ # # ]: 0 : assert(PyLong_Check(which_watcher));
332 : 0 : long which_l = PyLong_AsLong(which_watcher);
333 [ # # ]: 0 : if (which_l == 0) {
334 : 0 : watcher_id = PyCode_AddWatcher(first_code_object_callback);
335 : 0 : num_code_object_created_events[0] = 0;
336 : 0 : num_code_object_destroyed_events[0] = 0;
337 : : }
338 [ # # ]: 0 : else if (which_l == 1) {
339 : 0 : watcher_id = PyCode_AddWatcher(second_code_object_callback);
340 : 0 : num_code_object_created_events[1] = 0;
341 : 0 : num_code_object_destroyed_events[1] = 0;
342 : : }
343 [ # # ]: 0 : else if (which_l == 2) {
344 : 0 : watcher_id = PyCode_AddWatcher(error_code_event_handler);
345 : : }
346 : : else {
347 : 0 : PyErr_Format(PyExc_ValueError, "invalid watcher %d", which_l);
348 : 0 : return NULL;
349 : : }
350 [ # # ]: 0 : if (watcher_id < 0) {
351 : 0 : return NULL;
352 : : }
353 : 0 : return PyLong_FromLong(watcher_id);
354 : : }
355 : :
356 : : static PyObject *
357 : 0 : clear_code_watcher(PyObject *self, PyObject *watcher_id)
358 : : {
359 [ # # ]: 0 : assert(PyLong_Check(watcher_id));
360 : 0 : long watcher_id_l = PyLong_AsLong(watcher_id);
361 [ # # ]: 0 : if (PyCode_ClearWatcher(watcher_id_l) < 0) {
362 : 0 : return NULL;
363 : : }
364 : : // reset static events counters
365 [ # # # # ]: 0 : if (watcher_id_l >= 0 && watcher_id_l < NUM_CODE_WATCHERS) {
366 : 0 : num_code_object_created_events[watcher_id_l] = 0;
367 : 0 : num_code_object_destroyed_events[watcher_id_l] = 0;
368 : : }
369 : 0 : Py_RETURN_NONE;
370 : : }
371 : :
372 : : static PyObject *
373 : 0 : get_code_watcher_num_created_events(PyObject *self, PyObject *watcher_id)
374 : : {
375 [ # # ]: 0 : assert(PyLong_Check(watcher_id));
376 : 0 : long watcher_id_l = PyLong_AsLong(watcher_id);
377 [ # # # # ]: 0 : assert(watcher_id_l >= 0 && watcher_id_l < NUM_CODE_WATCHERS);
378 : 0 : return PyLong_FromLong(num_code_object_created_events[watcher_id_l]);
379 : : }
380 : :
381 : : static PyObject *
382 : 0 : get_code_watcher_num_destroyed_events(PyObject *self, PyObject *watcher_id)
383 : : {
384 [ # # ]: 0 : assert(PyLong_Check(watcher_id));
385 : 0 : long watcher_id_l = PyLong_AsLong(watcher_id);
386 [ # # # # ]: 0 : assert(watcher_id_l >= 0 && watcher_id_l < NUM_CODE_WATCHERS);
387 : 0 : return PyLong_FromLong(num_code_object_destroyed_events[watcher_id_l]);
388 : : }
389 : :
390 : : static PyObject *
391 : 0 : allocate_too_many_code_watchers(PyObject *self, PyObject *args)
392 : : {
393 : : int watcher_ids[CODE_MAX_WATCHERS + 1];
394 : 0 : int num_watchers = 0;
395 [ # # ]: 0 : for (unsigned long i = 0; i < sizeof(watcher_ids) / sizeof(int); i++) {
396 : 0 : int watcher_id = PyCode_AddWatcher(noop_code_event_handler);
397 [ # # ]: 0 : if (watcher_id == -1) {
398 : 0 : break;
399 : : }
400 : 0 : watcher_ids[i] = watcher_id;
401 : 0 : num_watchers++;
402 : : }
403 : 0 : PyObject *exc = PyErr_GetRaisedException();
404 [ # # ]: 0 : for (int i = 0; i < num_watchers; i++) {
405 [ # # ]: 0 : if (PyCode_ClearWatcher(watcher_ids[i]) < 0) {
406 : 0 : PyErr_WriteUnraisable(Py_None);
407 : 0 : break;
408 : : }
409 : : }
410 [ # # ]: 0 : if (exc) {
411 : 0 : PyErr_SetRaisedException(exc);
412 : 0 : return NULL;
413 : : }
414 [ # # ]: 0 : else if (PyErr_Occurred()) {
415 : 0 : return NULL;
416 : : }
417 : 0 : Py_RETURN_NONE;
418 : : }
419 : :
420 : : // Test function watchers
421 : :
422 : : #define NUM_FUNC_WATCHERS 2
423 : : static PyObject *pyfunc_watchers[NUM_FUNC_WATCHERS];
424 : : static int func_watcher_ids[NUM_FUNC_WATCHERS] = {-1, -1};
425 : :
426 : : static PyObject *
427 : 0 : get_id(PyObject *obj)
428 : : {
429 : 0 : PyObject *builtins = PyEval_GetBuiltins(); // borrowed ref.
430 [ # # ]: 0 : if (builtins == NULL) {
431 : 0 : return NULL;
432 : : }
433 : 0 : PyObject *id_str = PyUnicode_FromString("id");
434 [ # # ]: 0 : if (id_str == NULL) {
435 : 0 : return NULL;
436 : : }
437 : 0 : PyObject *id_func = PyObject_GetItem(builtins, id_str);
438 : 0 : Py_DECREF(id_str);
439 [ # # ]: 0 : if (id_func == NULL) {
440 : 0 : return NULL;
441 : : }
442 : 0 : PyObject *stack[] = {obj};
443 : 0 : PyObject *id = PyObject_Vectorcall(id_func, stack, 1, NULL);
444 : 0 : Py_DECREF(id_func);
445 : 0 : return id;
446 : : }
447 : :
448 : : static int
449 : 0 : call_pyfunc_watcher(PyObject *watcher, PyFunction_WatchEvent event,
450 : : PyFunctionObject *func, PyObject *new_value)
451 : : {
452 : 0 : PyObject *event_obj = PyLong_FromLong(event);
453 [ # # ]: 0 : if (event_obj == NULL) {
454 : 0 : return -1;
455 : : }
456 [ # # ]: 0 : if (new_value == NULL) {
457 : 0 : new_value = Py_None;
458 : : }
459 : 0 : Py_INCREF(new_value);
460 : 0 : PyObject *func_or_id = NULL;
461 [ # # ]: 0 : if (event == PyFunction_EVENT_DESTROY) {
462 : : /* Don't expose a function that's about to be destroyed to managed code */
463 : 0 : func_or_id = get_id((PyObject *) func);
464 [ # # ]: 0 : if (func_or_id == NULL) {
465 : 0 : Py_DECREF(event_obj);
466 : 0 : Py_DECREF(new_value);
467 : 0 : return -1;
468 : : }
469 : : }
470 : : else {
471 : 0 : Py_INCREF(func);
472 : 0 : func_or_id = (PyObject *) func;
473 : : }
474 : 0 : PyObject *stack[] = {event_obj, func_or_id, new_value};
475 : 0 : PyObject *res = PyObject_Vectorcall(watcher, stack, 3, NULL);
476 [ # # ]: 0 : int st = (res == NULL) ? -1 : 0;
477 : 0 : Py_XDECREF(res);
478 : 0 : Py_DECREF(new_value);
479 : 0 : Py_DECREF(event_obj);
480 : 0 : Py_DECREF(func_or_id);
481 : 0 : return st;
482 : : }
483 : :
484 : : static int
485 : 0 : first_func_watcher_callback(PyFunction_WatchEvent event, PyFunctionObject *func,
486 : : PyObject *new_value)
487 : : {
488 : 0 : return call_pyfunc_watcher(pyfunc_watchers[0], event, func, new_value);
489 : : }
490 : :
491 : : static int
492 : 0 : second_func_watcher_callback(PyFunction_WatchEvent event,
493 : : PyFunctionObject *func, PyObject *new_value)
494 : : {
495 : 0 : return call_pyfunc_watcher(pyfunc_watchers[1], event, func, new_value);
496 : : }
497 : :
498 : : static PyFunction_WatchCallback func_watcher_callbacks[NUM_FUNC_WATCHERS] = {
499 : : first_func_watcher_callback,
500 : : second_func_watcher_callback
501 : : };
502 : :
503 : : static int
504 : 10 : add_func_event(PyObject *module, const char *name, PyFunction_WatchEvent event)
505 : : {
506 : 10 : PyObject *value = PyLong_FromLong(event);
507 [ - + ]: 10 : if (value == NULL) {
508 : 0 : return -1;
509 : : }
510 : 10 : int ok = PyModule_AddObjectRef(module, name, value);
511 : 10 : Py_DECREF(value);
512 : 10 : return ok;
513 : : }
514 : :
515 : : static PyObject *
516 : 0 : add_func_watcher(PyObject *self, PyObject *func)
517 : : {
518 [ # # ]: 0 : if (!PyFunction_Check(func)) {
519 : 0 : PyErr_SetString(PyExc_TypeError, "'func' must be a function");
520 : 0 : return NULL;
521 : : }
522 : 0 : int idx = -1;
523 [ # # ]: 0 : for (int i = 0; i < NUM_FUNC_WATCHERS; i++) {
524 [ # # ]: 0 : if (func_watcher_ids[i] == -1) {
525 : 0 : idx = i;
526 : 0 : break;
527 : : }
528 : : }
529 [ # # ]: 0 : if (idx == -1) {
530 : 0 : PyErr_SetString(PyExc_RuntimeError, "no free watchers");
531 : 0 : return NULL;
532 : : }
533 : 0 : PyObject *result = PyLong_FromLong(idx);
534 [ # # ]: 0 : if (result == NULL) {
535 : 0 : return NULL;
536 : : }
537 : 0 : func_watcher_ids[idx] = PyFunction_AddWatcher(func_watcher_callbacks[idx]);
538 [ # # ]: 0 : if (func_watcher_ids[idx] < 0) {
539 : 0 : Py_DECREF(result);
540 : 0 : return NULL;
541 : : }
542 : 0 : pyfunc_watchers[idx] = Py_NewRef(func);
543 : 0 : return result;
544 : : }
545 : :
546 : : static PyObject *
547 : 0 : clear_func_watcher(PyObject *self, PyObject *watcher_id_obj)
548 : : {
549 : 0 : long watcher_id = PyLong_AsLong(watcher_id_obj);
550 [ # # # # ]: 0 : if ((watcher_id < INT_MIN) || (watcher_id > INT_MAX)) {
551 : 0 : PyErr_SetString(PyExc_ValueError, "invalid watcher ID");
552 : 0 : return NULL;
553 : : }
554 : 0 : int wid = (int) watcher_id;
555 [ # # ]: 0 : if (PyFunction_ClearWatcher(wid) < 0) {
556 : 0 : return NULL;
557 : : }
558 : 0 : int idx = -1;
559 [ # # ]: 0 : for (int i = 0; i < NUM_FUNC_WATCHERS; i++) {
560 [ # # ]: 0 : if (func_watcher_ids[i] == wid) {
561 : 0 : idx = i;
562 : 0 : break;
563 : : }
564 : : }
565 [ # # ]: 0 : assert(idx != -1);
566 [ # # ]: 0 : Py_CLEAR(pyfunc_watchers[idx]);
567 : 0 : func_watcher_ids[idx] = -1;
568 : 0 : Py_RETURN_NONE;
569 : : }
570 : :
571 : : static int
572 : 0 : noop_func_event_handler(PyFunction_WatchEvent event, PyFunctionObject *func,
573 : : PyObject *new_value)
574 : : {
575 : 0 : return 0;
576 : : }
577 : :
578 : : static PyObject *
579 : 0 : allocate_too_many_func_watchers(PyObject *self, PyObject *args)
580 : : {
581 : : int watcher_ids[FUNC_MAX_WATCHERS + 1];
582 : 0 : int num_watchers = 0;
583 [ # # ]: 0 : for (unsigned long i = 0; i < sizeof(watcher_ids) / sizeof(int); i++) {
584 : 0 : int watcher_id = PyFunction_AddWatcher(noop_func_event_handler);
585 [ # # ]: 0 : if (watcher_id == -1) {
586 : 0 : break;
587 : : }
588 : 0 : watcher_ids[i] = watcher_id;
589 : 0 : num_watchers++;
590 : : }
591 : 0 : PyObject *exc = PyErr_GetRaisedException();
592 [ # # ]: 0 : for (int i = 0; i < num_watchers; i++) {
593 [ # # ]: 0 : if (PyFunction_ClearWatcher(watcher_ids[i]) < 0) {
594 : 0 : PyErr_WriteUnraisable(Py_None);
595 : 0 : break;
596 : : }
597 : : }
598 [ # # ]: 0 : if (exc) {
599 : 0 : PyErr_SetRaisedException(exc);
600 : 0 : return NULL;
601 : : }
602 [ # # ]: 0 : else if (PyErr_Occurred()) {
603 : 0 : return NULL;
604 : : }
605 : 0 : Py_RETURN_NONE;
606 : : }
607 : :
608 : : static PyObject *
609 : 0 : set_func_defaults(PyObject *self, PyObject *args)
610 : : {
611 : 0 : PyObject *func = NULL;
612 : 0 : PyObject *defaults = NULL;
613 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) {
614 : 0 : return NULL;
615 : : }
616 [ # # ]: 0 : if (PyFunction_SetDefaults(func, defaults) < 0) {
617 : 0 : return NULL;
618 : : }
619 : 0 : Py_RETURN_NONE;
620 : : }
621 : :
622 : : static PyObject *
623 : 0 : set_func_kwdefaults(PyObject *self, PyObject *args)
624 : : {
625 : 0 : PyObject *func = NULL;
626 : 0 : PyObject *kwdefaults = NULL;
627 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "OO", &func, &kwdefaults)) {
628 : 0 : return NULL;
629 : : }
630 [ # # ]: 0 : if (PyFunction_SetKwDefaults(func, kwdefaults) < 0) {
631 : 0 : return NULL;
632 : : }
633 : 0 : Py_RETURN_NONE;
634 : : }
635 : :
636 : : static PyMethodDef test_methods[] = {
637 : : // Dict watchers.
638 : : {"add_dict_watcher", add_dict_watcher, METH_O, NULL},
639 : : {"clear_dict_watcher", clear_dict_watcher, METH_O, NULL},
640 : : {"watch_dict", watch_dict, METH_VARARGS, NULL},
641 : : {"unwatch_dict", unwatch_dict, METH_VARARGS, NULL},
642 : : {"get_dict_watcher_events",
643 : : (PyCFunction) get_dict_watcher_events, METH_NOARGS, NULL},
644 : :
645 : : // Type watchers.
646 : : {"add_type_watcher", add_type_watcher, METH_O, NULL},
647 : : {"clear_type_watcher", clear_type_watcher, METH_O, NULL},
648 : : {"watch_type", watch_type, METH_VARARGS, NULL},
649 : : {"unwatch_type", unwatch_type, METH_VARARGS, NULL},
650 : : {"get_type_modified_events",
651 : : (PyCFunction) get_type_modified_events, METH_NOARGS, NULL},
652 : :
653 : : // Code object watchers.
654 : : {"add_code_watcher", add_code_watcher, METH_O, NULL},
655 : : {"clear_code_watcher", clear_code_watcher, METH_O, NULL},
656 : : {"get_code_watcher_num_created_events",
657 : : get_code_watcher_num_created_events, METH_O, NULL},
658 : : {"get_code_watcher_num_destroyed_events",
659 : : get_code_watcher_num_destroyed_events, METH_O, NULL},
660 : : {"allocate_too_many_code_watchers",
661 : : (PyCFunction) allocate_too_many_code_watchers, METH_NOARGS, NULL},
662 : :
663 : : // Function watchers.
664 : : {"add_func_watcher", add_func_watcher, METH_O, NULL},
665 : : {"clear_func_watcher", clear_func_watcher, METH_O, NULL},
666 : : {"set_func_defaults_via_capi", set_func_defaults, METH_VARARGS, NULL},
667 : : {"set_func_kwdefaults_via_capi", set_func_kwdefaults, METH_VARARGS, NULL},
668 : : {"allocate_too_many_func_watchers", allocate_too_many_func_watchers,
669 : : METH_NOARGS, NULL},
670 : : {NULL},
671 : : };
672 : :
673 : : int
674 : 2 : _PyTestCapi_Init_Watchers(PyObject *mod)
675 : : {
676 [ - + ]: 2 : if (PyModule_AddFunctions(mod, test_methods) < 0) {
677 : 0 : return -1;
678 : : }
679 : :
680 : : /* Expose each event as an attribute on the module */
681 : : #define ADD_EVENT(event) \
682 : : if (add_func_event(mod, "PYFUNC_EVENT_" #event, \
683 : : PyFunction_EVENT_##event)) { \
684 : : return -1; \
685 : : }
686 [ - + - + : 2 : PY_FOREACH_FUNC_EVENT(ADD_EVENT);
- + - + -
+ ]
687 : : #undef ADD_EVENT
688 : :
689 : 2 : return 0;
690 : : }
|