[pypy-dev] Possibly a PyPy C-API bug

Johan Råde johan.rade at gmail.com
Sat Mar 8 14:42:52 CET 2014


Hi everyone,

I think I might have found a bug in the PyPy C-API.
It seems that PyType_Type.tp_new is broken.
Here is a minimal example that reproduces the bug.

Instructions:
	Compile Foo3.c as a python extension module named Foo3.
	Set up the paths so that Test3.py can find Foo3.
	Run Test3.py

Expected result and observed result with CPython 2.7.6:
	Test3.py runs

Observed result with PyPy 2.2.1:
	Test3.py crashes.
	(It gets into an infinite recursive loop where PyType_Type.tpnew and 
Foo3Type_Type.tp_new keep calling each other.)

Fixing this bug, or finding a workaround, would get me one step closer 
to getting PySide to run with PyPy.

Cheers,
Johan

-------------- next part --------------
#include <Python.h>

PyObject* foo3type_tp_new(PyTypeObject* metatype, PyObject* args, PyObject* kwds)
{
	// In a more realistic example we might do some preprocessing of args and kwargs here ...
    PyObject* newType = PyType_Type.tp_new(metatype, args, kwds);
	// ... and some postprocessing of newType here
	return newType;
}

PyTypeObject Foo3Type_Type = {
    PyVarObject_HEAD_INIT(0, 0)
    /*tp_name*/             "Foo3.Type",
    /*tp_basicsize*/        sizeof(PyTypeObject),
    /*tp_itemsize*/         0,
    /*tp_dealloc*/          0,
    /*tp_print*/            0,
    /*tp_getattr*/          0,
    /*tp_setattr*/          0,
    /*tp_compare*/          0,
    /*tp_repr*/             0,
    /*tp_as_number*/        0,
    /*tp_as_sequence*/      0,
    /*tp_as_mapping*/       0,
    /*tp_hash*/             0,
    /*tp_call*/             0,
    /*tp_str*/              0,
    /*tp_getattro*/         0,
    /*tp_setattro*/         0,
    /*tp_as_buffer*/        0,
    /*tp_flags*/            Py_TPFLAGS_DEFAULT,
    /*tp_doc*/              0,
    /*tp_traverse*/         0,
    /*tp_clear*/            0,
    /*tp_richcompare*/      0,
    /*tp_weaklistoffset*/   0,
    /*tp_iter*/             0,
    /*tp_iternext*/         0,
    /*tp_methods*/          0,
    /*tp_members*/          0,
    /*tp_getset*/           0,
    /*tp_base*/             0,		//  set to &PyType_Type in module init function (why can it not be done here?)
    /*tp_dict*/             0,
    /*tp_descr_get*/        0,
    /*tp_descr_set*/        0,
    /*tp_dictoffset*/       0,
    /*tp_init*/             0,
    /*tp_alloc*/            0,
    /*tp_new*/              foo3type_tp_new,
    /*tp_free*/             0,
    /*tp_is_gc*/            0,
    /*tp_bases*/            0,
    /*tp_mro*/              0,
    /*tp_cache*/            0,
    /*tp_subclasses*/       0,
    /*tp_weaklist*/         0
};

static PyMethodDef sbkMethods[] = {{NULL, NULL, 0, NULL}};

#ifdef _WIN32
	__declspec(dllexport) void		// PyModINIT_FUNC is broken on PyPy/Windows
#else
	PyMODINIT_FUNC
#endif
initFoo3(void)
{
	PyObject* mod = Py_InitModule("Foo3", sbkMethods);
	Foo3Type_Type.tp_base = &PyType_Type;
	PyType_Ready(&Foo3Type_Type);
	PyModule_AddObject(mod, "Type", (PyObject*)&Foo3Type_Type);
}
-------------- next part --------------
import Foo3

class X(object):
    __metaclass__ = Foo3.Type
    pass


More information about the pypy-dev mailing list