gh-106320: Remove private _PyObject C API (#107147)

Move private debug _PyObject functions to the internal C API
(pycore_object.h):

* _PyDebugAllocatorStats()
* _PyObject_CheckConsistency()
* _PyObject_DebugTypeStats()
* _PyObject_IsFreed()

No longer export most of these functions, except of
_PyObject_IsFreed().

Move test functions using _PyObject_IsFreed() from _testcapi to
_testinternalcapi. check_pyobject_is_freed() test no longer catch
_testcapi.error: the tested function cannot raise _testcapi.error.
This commit is contained in:
Victor Stinner 2023-07-23 22:09:08 +02:00 • committed by GitHub
parent 0810b0c435
commit 0d6dfd68d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 116 additions and 112 deletions

View file

@ -526,75 +526,6 @@ pymem_malloc_without_gil(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
static PyObject *
test_pyobject_is_freed(const char *test_name, PyObject *op)
{
if (!_PyObject_IsFreed(op)) {
PyErr_SetString(PyExc_AssertionError,
"object is not seen as freed");
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
check_pyobject_null_is_freed(PyObject *self, PyObject *Py_UNUSED(args))
{
PyObject *op = NULL;
return test_pyobject_is_freed("check_pyobject_null_is_freed", op);
}
static PyObject *
check_pyobject_uninitialized_is_freed(PyObject *self,
PyObject *Py_UNUSED(args))
{
PyObject *op = (PyObject *)PyObject_Malloc(sizeof(PyObject));
if (op == NULL) {
return NULL;
}
/* Initialize reference count to avoid early crash in ceval or GC */
Py_SET_REFCNT(op, 1);
/* object fields like ob_type are uninitialized! */
return test_pyobject_is_freed("check_pyobject_uninitialized_is_freed", op);
}
static PyObject *
check_pyobject_forbidden_bytes_is_freed(PyObject *self,
PyObject *Py_UNUSED(args))
{
/* Allocate an incomplete PyObject structure: truncate 'ob_type' field */
PyObject *op = (PyObject *)PyObject_Malloc(offsetof(PyObject, ob_type));
if (op == NULL) {
return NULL;
}
/* Initialize reference count to avoid early crash in ceval or GC */
Py_SET_REFCNT(op, 1);
/* ob_type field is after the memory block: part of "forbidden bytes"
when using debug hooks on memory allocators! */
return test_pyobject_is_freed("check_pyobject_forbidden_bytes_is_freed", op);
}
static PyObject *
check_pyobject_freed_is_freed(PyObject *self, PyObject *Py_UNUSED(args))
{
/* This test would fail if run with the address sanitizer */
#ifdef _Py_ADDRESS_SANITIZER
Py_RETURN_NONE;
#else
PyObject *op = PyObject_CallNoArgs((PyObject *)&PyBaseObject_Type);
if (op == NULL) {
return NULL;
}
Py_TYPE(op)->tp_dealloc(op);
/* Reset reference count to avoid early crash in ceval or GC */
Py_SET_REFCNT(op, 1);
/* object memory is freed! */
return test_pyobject_is_freed("check_pyobject_freed_is_freed", op);
#endif
}
// Tracemalloc tests
static PyObject *
@ -656,12 +587,6 @@ tracemalloc_untrack(PyObject *self, PyObject *args)
}
static PyMethodDef test_methods[] = {
{"check_pyobject_forbidden_bytes_is_freed",
check_pyobject_forbidden_bytes_is_freed, METH_NOARGS},
{"check_pyobject_freed_is_freed", check_pyobject_freed_is_freed, METH_NOARGS},
{"check_pyobject_null_is_freed", check_pyobject_null_is_freed, METH_NOARGS},
{"check_pyobject_uninitialized_is_freed",
check_pyobject_uninitialized_is_freed, METH_NOARGS},
{"pymem_api_misuse", pymem_api_misuse, METH_NOARGS},
{"pymem_buffer_overflow", pymem_buffer_overflow, METH_NOARGS},
{"pymem_getallocatorsname", test_pymem_getallocatorsname, METH_NOARGS},