0

I'm trying to run the following C function via Python and get the segmentation error.

void WKMV(
    const double *const time2,
    const int *const status,
    const double *const weights,
    const int *const delta,
    const int *const len,
    const int *const end,
    double *const surv)
{
    register int i;
    double n, d;
    *surv = 1;
    for (i = *len-1, n = 0; i >= *end; i--) { // loop in reverse order until end index is reached
        n += delta[i]*weights[i]; // initialize living weighting
    }
    while (i >= 0) { // loop through the sample in reverse order until zero index is reached
        n += delta[i]*weights[i];
        d = status[i]*weights[i]; // initialize dead weighting
        for (i--; i >= 0 && time2[i] == time2[i+1]; i--) { // loop in reverse order until time changes or zero index is reached
            n += delta[i]*weights[i]; // weight the living
            d += status[i]*weights[i]; // weight the dead
        }
        if (n > 0) *surv *= 1-d/n; // compute survival probability
    }
    return;

I am using Python Ctypes package like so. For the ease of play I have added a hardcoded data for each argument.

from ctypes import *

c_funcs = CDLL('filepath/file.so')
WKMV = c_funcs.WKMV

def do_WKMV_using_c():


    """Call C function"""

    n = 10

    # Declaring the variables
    time2 = [58.72, 41.9, 16.23, 145.44, 10.56, 54.95, 196.46, 194.03, 20.95, 20.0]
    status = [1, 1, 0, 0, 0, 0, 0, 0, 1, 0]
    time1 = [6.36, 4.91, 6.53, 4.77, 5.59, 6.9, 3.05, 6.17, 5.19, 6.41]
    delta = [1]*n
    weights = [0.5]*n
    surv = 1.0


    #Converting variables to format readable to C
    c_arr_time2 = (c_double * n)(*time2)
    c_arr_status = (c_int * n)(*status)
    c_arr_weights = (c_double * n)(*weights)
    c_arr_delta = (c_int * n)(*delta)
    c_int_len = c_int(n)
    c_float_surv = c_double(surv)
    c_int_end = c_int(n)

    WeightedKaplanMeierValue.restype = None
    WeightedKaplanMeierValue(c_arr_time2,c_arr_status, c_arr_weights, c_arr_delta,
                             c_int_len, c_int_end, c_float_surv)

    c_res_out = c_float_surv

    return c_res_out

print(do_WKMV_using_c())

I get the following error

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

From the looks of it I have translated all of the arguments into readable C code. Also as I can see(I am a noob at C) that there are no internal functions within the C function. So not sure where the error is. Also is there are way to get more detailed error message from C? Any help on that?

3
  • Did you try to test that function alone, in C, without involving Python? Commented Jun 15, 2022 at 16:36
  • Duplicate of stackoverflow.com/questions/58610333? Commented Jun 16, 2022 at 9:59
  • Please extract a minimal reproducible example, there are too many things that could go wrong. Also, use C's assert() macro to ensure that pointers are non-null. Commented Jun 16, 2022 at 21:21

1 Answer 1

1

The error is not setting .argtypes so ctypes can check that parameters are passed correctly. If set, the Python code would error indicating some parameters weren't correct. Here's the fix:

test.py - commented changed code

from ctypes import *

c_funcs = CDLL('./test')
WeightedKaplanMeierValue = c_funcs.WKMV
# added .argtypes
WeightedKaplanMeierValue.argtypes = (POINTER(c_double), POINTER(c_int), POINTER(c_double),
                                     POINTER(c_int), POINTER(c_int), POINTER(c_int), POINTER(c_double))
WeightedKaplanMeierValue.restype = None

def do_WKMV_using_c():
    n = 10
    time2 = [58.72, 41.9, 16.23, 145.44, 10.56, 54.95, 196.46, 194.03, 20.95, 20.0]
    status = [1, 1, 0, 0, 0, 0, 0, 0, 1, 0]
    time1 = [6.36, 4.91, 6.53, 4.77, 5.59, 6.9, 3.05, 6.17, 5.19, 6.41]
    delta = [1]*n
    weights = [0.5]*n
    surv = 1.0

    c_arr_time2 = (c_double * n)(*time2)
    c_arr_status = (c_int * n)(*status)
    c_arr_weights = (c_double * n)(*weights)
    c_arr_delta = (c_int * n)(*delta)
    c_int_len = c_int(n)
    c_float_surv = c_double(surv)
    c_int_end = c_int(n)

# Pass the address of the last three scalar values.
WeightedKaplanMeierValue(c_arr_time2, c_arr_status, c_arr_weights, c_arr_delta,
                             byref(c_int_len), byref(c_int_end), byref(c_float_surv))

    # Add .value to extract the Python object.
    return c_float_surv.value

print(do_WKMV_using_c())

test.c - DLL used to test. No changes to OP code except to export the function on Windows.

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

API void WKMV(
    const double *const time2,
    const int *const status,
    const double *const weights,
    const int *const delta,
    const int *const len,
    const int *const end,
    double *const surv)
{
    register int i;
    double n, d;
    *surv = 1;
    for (i = *len-1, n = 0; i >= *end; i--) { // loop in reverse order until end index is reached
        n += delta[i]*weights[i]; // initialize living weighting
    }
    while (i >= 0) { // loop through the sample in reverse order until zero index is reached
        n += delta[i]*weights[i];
        d = status[i]*weights[i]; // initialize dead weighting
        for (i--; i >= 0 && time2[i] == time2[i+1]; i--) { // loop in reverse order until time changes or zero index is reached
            n += delta[i]*weights[i]; // weight the living
            d += status[i]*weights[i]; // weight the dead
        }
        if (n > 0) *surv *= 1-d/n; // compute survival probability
    }
    return;
}

Output:

0.39999999999999997
Sign up to request clarification or add additional context in comments.

2 Comments

Brilliant thanks! That worked. Sorry for the late reply. It works without the byref() for me as well. Can you explain why do I need to use it?
@YuryMoskaltsov Because .argtypes is set, ctypes knows for example that if you pass a c_int() and .argtypes says the parameter should be a POINTER(c_int) type that it can do the byref for you. It's a good habit to always set .argtypes and .restype so ctypes can do these checks for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.