Skip to content

Commit

Permalink
Fix the test.
Browse files Browse the repository at this point in the history
  • Loading branch information
ericsnowcurrently committed Jun 1, 2023
1 parent 08a0321 commit 80d20c6
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 40 deletions.
27 changes: 17 additions & 10 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1629,27 +1629,34 @@ def test_tp_mro_is_set(self):

class TestStaticTypes(unittest.TestCase):

_has_run = False

@classmethod
def setUpClass(cls):
# The tests here don't play nice with our approach to refleak
# detection, so we bail out in that case.
if cls._has_run:
raise unittest.SkipTest('these tests do not support re-running')
cls._has_run = True

@contextlib.contextmanager
def basic_static_type(self, *args):
cls = _testcapi.get_basic_static_type(*args)
yield cls

def test_pytype_ready_always_sets_tp_type(self):
# The point of this test is to prevent something like
# https://github.com/python/cpython/issues/104614
# from happening again.

@contextlib.contextmanager
def basic_static_type(*args):
cls = _testcapi.get_basic_static_type(*args)
try:
yield cls
finally:
_testcapi.clear_basic_static_type(cls)

# First check when tp_base/tp_bases is *not* set before PyType_Ready().
with basic_static_type() as cls:
with self.basic_static_type() as cls:
self.assertIs(cls.__base__, object);
self.assertEqual(cls.__bases__, (object,));
self.assertIs(type(cls), type(object));

# Then check when we *do* set tp_base/tp_bases first.
with basic_static_type(object) as cls:
with self.basic_static_type(object) as cls:
self.assertIs(cls.__base__, object);
self.assertEqual(cls.__bases__, (object,));
self.assertIs(type(cls), type(object));
Expand Down
47 changes: 18 additions & 29 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2627,13 +2627,20 @@ type_get_tp_mro(PyObject *self, PyObject *type)
}


static PyTypeObject BasicStaticType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "BasicStaticType",
.tp_basicsize = sizeof(PyObject),
/* We only use 2 in test_capi/test_misc.py. */
#define NUM_BASIC_STATIC_TYPES 2
static PyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = {
#define INIT_BASIC_STATIC_TYPE \
{ \
PyVarObject_HEAD_INIT(NULL, 0) \
.tp_name = "BasicStaticType", \
.tp_basicsize = sizeof(PyObject), \
}
INIT_BASIC_STATIC_TYPE,
INIT_BASIC_STATIC_TYPE,
#undef INIT_BASIC_STATIC_TYPE
};

static PyObject * clear_basic_static_type(PyObject *, PyObject *);
static int num_basic_static_types_used = 0;

static PyObject *
get_basic_static_type(PyObject *self, PyObject *args)
Expand All @@ -2644,42 +2651,25 @@ get_basic_static_type(PyObject *self, PyObject *args)
}
assert(base == NULL || PyType_Check(base));

PyTypeObject *cls = &BasicStaticType;
assert(!(cls->tp_flags & Py_TPFLAGS_READY));
if(num_basic_static_types_used >= NUM_BASIC_STATIC_TYPES) {
PyErr_SetString(PyExc_RuntimeError, "no more available basic static types");
return NULL;
}
PyTypeObject *cls = &BasicStaticTypes[num_basic_static_types_used++];

if (base != NULL) {
cls->tp_base = (PyTypeObject *)Py_NewRef(base);
cls->tp_bases = Py_BuildValue("(O)", base);
if (cls->tp_bases == NULL) {
clear_basic_static_type(self, (PyObject *)cls);
return NULL;
}
}
if (PyType_Ready(cls) < 0) {
clear_basic_static_type(self, (PyObject *)cls);
return NULL;
}
Py_INCREF(cls);
return (PyObject *)cls;
}

static PyObject *
clear_basic_static_type(PyObject *self, PyObject *clsobj)
{
// Reset it back to the statically initialized state.
PyTypeObject *cls = (PyTypeObject *)clsobj;
Py_CLEAR(cls->ob_base.ob_base.ob_type);
Py_CLEAR(cls->tp_base);
Py_CLEAR(cls->tp_bases);
Py_CLEAR(cls->tp_mro);
Py_CLEAR(cls->tp_subclasses);
Py_CLEAR(cls->tp_dict);
cls->tp_flags &= ~Py_TPFLAGS_READY;
cls->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
cls->tp_version_tag = 0;
Py_RETURN_NONE;
}


// Test PyThreadState C API
static PyObject *
Expand Down Expand Up @@ -3439,7 +3429,6 @@ static PyMethodDef TestMethods[] = {
{"type_get_tp_bases", type_get_tp_bases, METH_O},
{"type_get_tp_mro", type_get_tp_mro, METH_O},
{"get_basic_static_type", get_basic_static_type, METH_VARARGS, NULL},
{"clear_basic_static_type", clear_basic_static_type, METH_O, NULL},
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
{"frame_getlocals", frame_getlocals, METH_O, NULL},
{"frame_getglobals", frame_getglobals, METH_O, NULL},
Expand Down
3 changes: 2 additions & 1 deletion Tools/c-analyzer/cpython/ignored.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,8 @@ Modules/_testcapi/watchers.c - num_code_object_destroyed_events -
Modules/_testcapi/watchers.c - pyfunc_watchers -
Modules/_testcapi/watchers.c - func_watcher_ids -
Modules/_testcapi/watchers.c - func_watcher_callbacks -
Modules/_testcapimodule.c - BasicStaticType -
Modules/_testcapimodule.c - BasicStaticTypes -
Modules/_testcapimodule.c - num_basic_static_types_used -
Modules/_testcapimodule.c - ContainerNoGC_members -
Modules/_testcapimodule.c - ContainerNoGC_type -
Modules/_testcapimodule.c - FmData -
Expand Down

0 comments on commit 80d20c6

Please sign in to comment.