Search code examples
cdebuggingpython-c-api

Python C API segmentation fault


I was trying to pass an array from C to python and perform a simple arithmetic operation numpy.prod, but encountered a segmentation error. Could anybody help me point out where went wrong? Thank you!

#include <Python.h>
#include <stdio.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "/share/apps/anaconda2/pkgs/numpy-1.10.4-py27_1/lib/python2.7/site-packages/numpy/core/include/numpy/arrayobject.h"

double Array[4] = {1.0, 2.0, 3.0, 4.0};

double call_func(PyObject *func, double array[]){
        PyObject *args;
        PyObject *kwargs;
        PyObject *result;
        npy_intp dims[1] = {4};
        double retval;

        PyGILState_STATE state = PyGILState_Ensure();

        if (!PyCallable_Check(func)){
                printf("%s", "Function is not callable!\n");
        }

        args = PyArray_SimpleNewFromData(1, dims, NPY_FLOAT32, array);
        kwargs = NULL;

        result = PyObject_Call(func, args, kwargs);
        Py_DECREF(args);
        Py_XDECREF(kwargs);

        if (PyErr_Occurred()){
                PyErr_Print();
        }

        if (!PyFloat_Check(result)){
                printf("%s", "Callable did not return a float!");
        }

        retval = PyFloat_AsDouble(result);
        Py_DECREF(result);

        PyGILState_Release(state);
        return retval;
}

PyObject *import_name(const char *modname, const char *symbol){
        PyObject *mymodule = PyImport_ImportModule(modname);
        return PyObject_GetAttrString(mymodule, symbol);
}

void main(){
        PyObject *myfunc;
        double retval;

        import_array();

        Py_Initialize();

        myfunc = import_name("numpy", "prod");

        retval = call_func(myfunc, Array);
        Py_DECREF(myfunc);

        printf("%d\n", retval);

        Py_Finalize();
}

(I followed the procedure on this website http://blog.numerix-dsp.com/2013/08/how-to-pass-c-array-to-python-solution.html?m=1.)


Solution

  • In addition to constructing your array object wrongly, as described in comments, the second argument to your PyObject_Call() call appears wrong. Per its docs, the second argument should point to a tuple, which in your case should contain your array object as its single element, but you pass the array object itself. Depending on how carefully that function or maybe the called function checks its arguments, that mismatch could easily cause a segfault.

    Additionally, if there are no keyword args then you can just pass a literal NULL as the third argument. In any case, since you can be certain that variable kwargs is NULL, it seems a bit pointless (albeit not erroneous) to Py_XDECREF() it.