summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2023-07-23 20:09:08 (GMT)
committerGitHub <noreply@github.com>2023-07-23 20:09:08 (GMT)
commit0d6dfd68d22762c115d202515fe3310bfb42e327 (patch)
treed20012091337f17a311bcc2309b3b03eedc94377 /Modules
parent0810b0c435415c09c1907c6f418585bed558a2c1 (diff)
downloadcpython-0d6dfd68d22762c115d202515fe3310bfb42e327.zip
cpython-0d6dfd68d22762c115d202515fe3310bfb42e327.tar.gz
cpython-0d6dfd68d22762c115d202515fe3310bfb42e327.tar.bz2
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.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_testcapi/mem.c75
-rw-r--r--Modules/_testclinic.c1
-rw-r--r--Modules/_testinternalcapi.c81
3 files changed, 81 insertions, 76 deletions
diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c
index 979b3a4..0b2b1cd 100644
--- a/Modules/_testcapi/mem.c
+++ b/Modules/_testcapi/mem.c
@@ -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},
diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c
index 26cdb43..8ba8f8e 100644
--- a/Modules/_testclinic.c
+++ b/Modules/_testclinic.c
@@ -6,6 +6,7 @@
#undef NDEBUG
#include "Python.h"
+#include "pycore_object.h" // _PyObject_IsFreed()
// Used for clone_with_conv_f1 and clone_with_conv_v2
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index ecc2721..e2be9a1 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -10,7 +10,6 @@
#undef NDEBUG
#include "Python.h"
-#include "frameobject.h"
#include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
#include "pycore_bitutils.h" // _Py_bswap32()
#include "pycore_bytesobject.h" // _PyBytes_Find()
@@ -23,9 +22,12 @@
#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy()
#include "pycore_interp_id.h" // _PyInterpreterID_LookUp()
+#include "pycore_object.h" // _PyObject_IsFreed()
#include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal()
#include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost()
#include "pycore_pystate.h" // _PyThreadState_GET()
+
+#include "frameobject.h"
#include "osdefs.h" // MAXPATHLEN
#include "clinic/_testinternalcapi.c.h"
@@ -1446,6 +1448,77 @@ test_atexit(PyObject *self, PyObject *Py_UNUSED(args))
}
+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
+}
+
+
static PyMethodDef module_functions[] = {
{"get_configs", get_configs, METH_NOARGS},
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
@@ -1502,6 +1575,12 @@ static PyMethodDef module_functions[] = {
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
{"_PyUnicode_TransformDecimalAndSpaceToASCII", unicode_transformdecimalandspacetoascii, METH_O},
{"test_atexit", test_atexit, METH_NOARGS},
+ {"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},
{NULL, NULL} /* sentinel */
};