Search code examples
pythonpython-c-apicpython

New python type created but PyGetSetDef core dumps


I have below code which tries to create a new type and use getter method to access value.

#include <Python.h>
#include <structmember.h>

struct rangerr {
        long    min;
        long    max;
};

//Python type to represent rangerr
struct py_rangerr {
    PyObject_HEAD
    struct rangerr range;
};
// * get & set methods for py_rangerr

static PyObject * py_rangerr_min_get(struct py_rangerr *self) {
    self->range.min  = 1;
        return PyLong_FromLong(self->range.min);
}

static PyObject * py_rangerr_max_get(struct py_rangerr *self) {
    self->range.max  = 10;
        return PyLong_FromLong(self->range.max);
}


//* GetSet method definition for py_rangerr
static PyGetSetDef py_rangerr_getset[] = {
    {"min",(getter)py_rangerr_min_get, NULL, "min",NULL},
    {"max",(getter)py_rangerr_max_get, NULL, "max",NULL},

    /* Sentinel */
    {NULL},
};

/******************************************************************************
 */
static void py_rangerr_dealloc(struct py_rangerr *self) { 
        self->ob_type->tp_free((PyObject *)self);               
}

static PyTypeObject py_rangerr_type = {  
    PyObject_HEAD_INIT(NULL)                      
    .tp_basicsize = sizeof(struct py_rangerr),
    .tp_dealloc   = (destructor) py_rangerr_dealloc,  
    .tp_flags     = Py_TPFLAGS_DEFAULT,                        
    .tp_alloc     = PyType_GenericAlloc,                       
    .tp_doc       = "rangerr",                                 
    .tp_getset    = py_rangerr_getset,                
};

void
initrangerr(void)
{
   PyObject* mod;

 mod = Py_InitModule3("rangerr", NULL, "An extension with a type.");
   if (mod == NULL) {
      return;
   }
  py_rangerr_type.tp_new = PyType_GenericNew;
  if (PyType_Ready(&py_rangerr_type) < 0){
      return;
   }


 Py_INCREF(&py_rangerr_type);
   PyModule_AddObject(mod, "rangerr", (PyObject*)&py_rangerr_type);

}

I can import the new type

import rangerr as r1

but accessing the getting method crashes

print r1.rangerr.min

EDIT:

(gdb) bt
#0  0x0000003a93331890 in __strrchr_sse42 () from /lib64/libc.so.6
#1  0x0000003a9c29b72b in ?? () from /lib64/libpython2.7.so.1.0
#2  0x0000003a9c29b922 in ?? () from /lib64/libpython2.7.so.1.0
#3  0x0000003a9c282d7a in _PyObject_Str () from /lib64/libpython2.7.so.1.0
#4  0x0000003a9c282e4a in PyObject_Str () from /lib64/libpython2.7.so.1.0
#5  0x0000003a9c282ff5 in ?? () from /lib64/libpython2.7.so.1.0
#6  0x0000003a9c266a88 in PyFile_WriteObject () from /lib64/libpython2.7.so.1.0
#7  0x0000003a9c2db09d in PyEval_EvalFrameEx () from /lib64/libpython2.7.so.1.0
#8  0x0000003a9c2ddcbf in PyEval_EvalCodeEx () from /lib64/libpython2.7.so.1.0
#9  0x0000003a9c2ddd92 in PyEval_EvalCode () from /lib64/libpython2.7.so.1.0
#10 0x0000003a9c2f6f7a in ?? () from /lib64/libpython2.7.so.1.0
#11 0x0000003a9c2f8c04 in PyRun_InteractiveOneFlags () from /lib64/libpython2.7.so.1.0
#12 0x0000003a9c2f8dde in PyRun_InteractiveLoopFlags () from /lib64/libpython2.7.so.1.0
#13 0x0000003a9c2f937c in PyRun_AnyFileExFlags () from /lib64/libpython2.7.so.1.0
#14 0x0000003a9c309c52 in Py_Main () from /lib64/libpython2.7.so.1.0
#15 0x0000003a93221a05 in __libc_start_main () from /lib64/libc.so.6
#16 0x0000000000400721 in _start ()
(gdb) 

Solution

  • You need to define tp_name. At the moment this field is not set at all.

    static PyTypeObject py_rangerr_type = {
        [...]
        .tp_name = "rangerr.rangerr",
        [...]
    };
    

    You're getting the core dump here, because Python tries to display the name of the type:

    >>> print r1.rangerr.min
    <attribute 'min' of 'rangerr.rangerr' objects>