cpython/Modules/_testcapi/code.c
Serhiy Storchaka 9cd366462b
[3.12] gh-106033: Get rid of new occurrences of PyDict_GetItem and Py… (#106041)
[3.12] gh-106033: Get rid of new occurrences of PyDict_GetItem and PyObject_HasAttr (GH-106034)

These functions are broken by design because they discard any exceptions raised
inside, including MemoryError and KeyboardInterrupt.  They should not be
used in new code.
(cherry picked from commit 1d33d53780)
2023-06-24 16:36:34 -07:00

119 lines
3.2 KiB
C

#include "parts.h"
static Py_ssize_t
get_code_extra_index(PyInterpreterState* interp) {
Py_ssize_t result = -1;
static const char *key = "_testcapi.frame_evaluation.code_index";
PyObject *interp_dict = PyInterpreterState_GetDict(interp); // borrowed
assert(interp_dict); // real users would handle missing dict... somehow
PyObject *index_obj = _PyDict_GetItemStringWithError(interp_dict, key); // borrowed
Py_ssize_t index = 0;
if (!index_obj) {
if (PyErr_Occurred()) {
goto finally;
}
index = PyUnstable_Eval_RequestCodeExtraIndex(NULL);
if (index < 0 || PyErr_Occurred()) {
goto finally;
}
index_obj = PyLong_FromSsize_t(index); // strong ref
if (!index_obj) {
goto finally;
}
int res = PyDict_SetItemString(interp_dict, key, index_obj);
Py_DECREF(index_obj);
if (res < 0) {
goto finally;
}
}
else {
index = PyLong_AsSsize_t(index_obj);
if (index == -1 && PyErr_Occurred()) {
goto finally;
}
}
result = index;
finally:
return result;
}
static PyObject *
test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable))
{
PyObject *result = NULL;
PyObject *test_module = NULL;
PyObject *test_func = NULL;
// Get or initialize interpreter-specific code object storage index
PyInterpreterState *interp = PyInterpreterState_Get();
if (!interp) {
return NULL;
}
Py_ssize_t code_extra_index = get_code_extra_index(interp);
if (PyErr_Occurred()) {
goto finally;
}
// Get a function to test with
// This can be any Python function. Use `test.test_misc.testfunction`.
test_module = PyImport_ImportModule("test.test_capi.test_misc");
if (!test_module) {
goto finally;
}
test_func = PyObject_GetAttrString(test_module, "testfunction");
if (!test_func) {
goto finally;
}
PyObject *test_func_code = PyFunction_GetCode(test_func); // borrowed
if (!test_func_code) {
goto finally;
}
// Check the value is initially NULL
void *extra;
int res = PyUnstable_Code_GetExtra(test_func_code, code_extra_index, &extra);
if (res < 0) {
goto finally;
}
assert (extra == NULL);
// Set another code extra value
res = PyUnstable_Code_SetExtra(test_func_code, code_extra_index, (void*)(uintptr_t)77);
if (res < 0) {
goto finally;
}
// Assert it was set correctly
res = PyUnstable_Code_GetExtra(test_func_code, code_extra_index, &extra);
if (res < 0) {
goto finally;
}
assert ((uintptr_t)extra == 77);
// Revert to initial code extra value.
res = PyUnstable_Code_SetExtra(test_func_code, code_extra_index, NULL);
if (res < 0) {
goto finally;
}
result = Py_NewRef(Py_None);
finally:
Py_XDECREF(test_module);
Py_XDECREF(test_func);
return result;
}
static PyMethodDef TestMethods[] = {
{"test_code_extra", test_code_extra, METH_NOARGS},
{NULL},
};
int
_PyTestCapi_Init_Code(PyObject *m) {
if (PyModule_AddFunctions(m, TestMethods) < 0) {
return -1;
}
return 0;
}