cpython/Modules/_testcapi/object.c

208 lines
4.8 KiB
C
Raw Normal View History

#include "parts.h"
#include "util.h"
static PyObject *
call_pyobject_print(PyObject *self, PyObject * args)
{
PyObject *object;
PyObject *filename;
PyObject *print_raw;
FILE *fp;
int flags = 0;
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 3, 3,
&object, &filename, &print_raw)) {
return NULL;
}
fp = Py_fopen(filename, "w+");
if (Py_IsTrue(print_raw)) {
flags = Py_PRINT_RAW;
}
if (PyObject_Print(object, fp, flags) < 0) {
fclose(fp);
return NULL;
}
fclose(fp);
Py_RETURN_NONE;
}
static PyObject *
pyobject_print_null(PyObject *self, PyObject *args)
{
PyObject *filename;
FILE *fp;
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
return NULL;
}
fp = Py_fopen(filename, "w+");
if (PyObject_Print(NULL, fp, 0) < 0) {
fclose(fp);
return NULL;
}
fclose(fp);
Py_RETURN_NONE;
}
static PyObject *
pyobject_print_noref_object(PyObject *self, PyObject *args)
{
PyObject *test_string;
PyObject *filename;
FILE *fp;
char correct_string[100];
test_string = PyUnicode_FromString("Spam spam spam");
Py_SET_REFCNT(test_string, 0);
PyOS_snprintf(correct_string, 100, "<refcnt %zd at %p>",
Py_REFCNT(test_string), (void *)test_string);
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
return NULL;
}
fp = Py_fopen(filename, "w+");
if (PyObject_Print(test_string, fp, 0) < 0){
fclose(fp);
Py_SET_REFCNT(test_string, 1);
Py_DECREF(test_string);
return NULL;
}
fclose(fp);
Py_SET_REFCNT(test_string, 1);
Py_DECREF(test_string);
return PyUnicode_FromString(correct_string);
}
static PyObject *
pyobject_print_os_error(PyObject *self, PyObject *args)
{
PyObject *test_string;
PyObject *filename;
FILE *fp;
test_string = PyUnicode_FromString("Spam spam spam");
if (!PyArg_UnpackTuple(args, "call_pyobject_print", 1, 1, &filename)) {
return NULL;
}
// open file in read mode to induce OSError
fp = Py_fopen(filename, "r");
if (PyObject_Print(test_string, fp, 0) < 0) {
fclose(fp);
Py_DECREF(test_string);
return NULL;
}
fclose(fp);
Py_DECREF(test_string);
Py_RETURN_NONE;
}
static PyObject *
pyobject_clear_weakrefs_no_callbacks(PyObject *self, PyObject *obj)
{
PyUnstable_Object_ClearWeakRefsNoCallbacks(obj);
Py_RETURN_NONE;
}
static PyObject *
pyobject_enable_deferred_refcount(PyObject *self, PyObject *obj)
{
int result = PyUnstable_Object_EnableDeferredRefcount(obj);
return PyLong_FromLong(result);
}
static int MyObject_dealloc_called = 0;
static void
MyObject_dealloc(PyObject *op)
{
// PyUnstable_TryIncRef should return 0 if object is being deallocated
assert(Py_REFCNT(op) == 0);
assert(!PyUnstable_TryIncRef(op));
assert(Py_REFCNT(op) == 0);
MyObject_dealloc_called++;
Py_TYPE(op)->tp_free(op);
}
static PyTypeObject MyType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "MyType",
.tp_basicsize = sizeof(PyObject),
.tp_dealloc = MyObject_dealloc,
};
static PyObject *
test_py_try_inc_ref(PyObject *self, PyObject *unused)
{
if (PyType_Ready(&MyType) < 0) {
return NULL;
}
MyObject_dealloc_called = 0;
PyObject *op = PyObject_New(PyObject, &MyType);
if (op == NULL) {
return NULL;
}
PyUnstable_EnableTryIncRef(op);
#ifdef Py_GIL_DISABLED
// PyUnstable_EnableTryIncRef sets the shared flags to
// `_Py_REF_MAYBE_WEAKREF` if the flags are currently zero to ensure that
// the shared reference count is merged on deallocation.
assert((op->ob_ref_shared & _Py_REF_SHARED_FLAG_MASK) >= _Py_REF_MAYBE_WEAKREF);
#endif
if (!PyUnstable_TryIncRef(op)) {
PyErr_SetString(PyExc_AssertionError, "PyUnstable_TryIncRef failed");
Py_DECREF(op);
return NULL;
}
Py_DECREF(op); // undo try-incref
Py_DECREF(op); // dealloc
assert(MyObject_dealloc_called == 1);
Py_RETURN_NONE;
}
static PyMethodDef test_methods[] = {
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
{"pyobject_print_null", pyobject_print_null, METH_VARARGS},
{"pyobject_print_noref_object", pyobject_print_noref_object, METH_VARARGS},
{"pyobject_print_os_error", pyobject_print_os_error, METH_VARARGS},
{"pyobject_clear_weakrefs_no_callbacks", pyobject_clear_weakrefs_no_callbacks, METH_O},
{"pyobject_enable_deferred_refcount", pyobject_enable_deferred_refcount, METH_O},
{"test_py_try_inc_ref", test_py_try_inc_ref, METH_NOARGS},
{NULL},
};
int
_PyTestCapi_Init_Object(PyObject *m)
{
if (PyModule_AddFunctions(m, test_methods) < 0) {
return -1;
}
return 0;
}