1

I'm trying to create a Cython function that depends on a Python function. The arguments of this Python function include a float and an array (I'm using Numpy arrays). I tried to follow this example Python/Cython/C and callbacks, calling a Python function from C using Cython but my code segfaults when is trying to access the array passed to the Python function. I have to make a callback function since I cannot pass a Python function to the C function directly. Below is a minimal example (my code is more complex than this example but the problem is the same)

example.py:

import numpy as np
from example_cython import my_function


def python_fun(x, x_arr):
    """
    Add x to the elements of x_arr
    """ 
    x_arr += x
    return 0.0


A = np.arange(3.)
B = np.ones(3, dtype=np.float)
n = 3
x = 2.
# Call the C function using the Python one
my_function(A, B, n, x, python_fun)

example.c

#include<stdio.h>

// Add x to the elements of *a and then add the elements of *a to *b
void C_fun(double * a, double * b, int n, double x,
           double (*f) (double, double *) 
           ) {

    printf("a: %f b: %f x: %f\n", a[0], b[0], x);

    // Update array a
    f(x, a);

    for(int i=0; i<n; i++) b[i] += a[i]; 
}

example.h

void C_fun(double * a, double * b, int n, double x,
           double (*f) (double, double *) 
           );

example_cython.pyx

# Function prototype for the C function
ctypedef double (*cfunction)(double x, double * y)
cdef object f

cdef extern from "example.h":
    void C_fun(double * a, double * b, int n, double x,
               double (*f) (double, double *) 
               )

cdef double cfunction_cb(double x, double [:] y):
    global f
    result = f(x, y)
    return result

# This function calls the f function (a Python f) that updates *a and then sums
# the elements of *a into *b
def my_function(double [:] a, double [:] b, int n, double x, pythonf):
    global f
    f = pythonf
    C_fun(&a[0], &b[0], n, x, <cfunction> cfunction_cb)

setup.py

from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension

extension_src = ["example_cython.pyx", "example.c"]
extensions = [
    Extension("example_cython", extension_src)
]
setup(
    ext_modules=cythonize(extensions),
)

Compiling the Cython module works, and I can access the C function and print the array contents, but when the function calls the array, it has the problem

a: 0.000000 b: 1.000000 x: 2.000000
[1]    791 segmentation fault (core dumped)  python example.py
PerroNoob
  • 843
  • 2
  • 16
  • 36
  • in `cdef double cfunction_cb(double x, double [:] y)`, `double [:]` is a typed memory view, what you want to use in the signature is a `double *` – ead Feb 21 '19 at 22:21
  • 1
    If you use more than one callback simultaniously, using runtime generated closures is a better solution, see https://stackoverflow.com/a/51054667/5769463 – ead Feb 21 '19 at 22:26
  • @ead that gives me an error: `Cannot convert 'double *' to Python object` – PerroNoob Feb 21 '19 at 22:32
  • 1
    which is better than segfault in my optinion - because now you see what you are doing wrong. – ead Feb 21 '19 at 22:37
  • Your problem is: you use ` cfunction_cb` which let the compiler cast the types no matter what, you should use `&cfunction_cb` instead - in this case compiler would check the types and you could see the type-mismatch. – ead Feb 21 '19 at 22:45

0 Answers0