Cython аварийно завершает работу ядра Python при запуске кода, который передает структуру указателей в функцию c

1

Получение ошибок распределения памяти при запуске скомпилированной версии следующего кода. Это приложение, в котором определена структура указателей, и я хотел бы присвоить значение указателю, а затем передать эту структуру в c-код. Я видел другие примеры и вопросы по этому вопросу, и я считаю, что это делается правильно, однако все еще возникают проблемы.

Код будет компилироваться отлично, однако он запускает Python при его запуске. Отладка с помощью Visual Studio показывает нарушение доступа к памяти. Я исследовал это совсем немного, но не могу придумать, почему это происходит. Был способен воспроизвести это на другом компьютере.

Я считаю, что это имеет какое-то отношение к тому, как struct test_M выделяется и ссылается на стек. Я пробовал несколько разных вариантов определения test_M.param.gain_val, показанный код позволяет компилировать код, и я могу получить вывод для печати на экране. Однако после этого Python аварийно завершает работу.

К сожалению, я не могу изменить код c, потому что это автоматически сгенерированный код из встроенного кодера Matlab/Simulink.

Любая помощь будет оценена по достоинству.

Using:
python = 3.6
cython = 0.26
numpy = 1.13.1
Visual Studio 2017 v15

ccodetest.c

#include <stdlib.h>

typedef struct P_T_ P_T;
typedef struct tag_T RT_MODEL_T;

struct P_T_ {
double gain_val;
};

struct tag_T {
  P_T *param;
};

void compute(double array_in[4], RT_MODEL_T *const test_M)
{
    P_T *test_P = ((P_T *) test_M->param);

    int size;
    size = sizeof(array_in);
    int i;
    for (i=0; i<size; i++)
    {
    array_in[i] = array_in[i] * test_P->gain_val;
    }

}

cython_param_test.pyx

cimport cython
import numpy as np
cimport numpy as np
from cpython.mem cimport PyMem_Malloc, PyMem_Free
np.import_array()

cdef extern from "ccodetest.c":
    ctypedef tag_T RT_MODEL_T
    ctypedef P_T_ P_T
    cdef struct P_T_:
        double gain_val
    cdef struct tag_T:
        P_T *param
    void compute(double array_in[4], RT_MODEL_T *const test_M)

cdef double array_in[4]

def run(
        np.ndarray[np.double_t, ndim=1, mode='c'] x_in,
        np.ndarray[np.double_t, ndim=2, mode='c'] x_out,
        np.ndarray[np.double_t, ndim=1, mode='c'] gain):

    cdef RT_MODEL_T* test_M = <RT_MODEL_T*> PyMem_Malloc(sizeof(RT_MODEL_T))

    global array_in

    test_M.param.gain_val = <double>gain
    cdef int idx

    try:

        for idx in range(len(x_in)):
            array_in[idx] = x_in[idx]

        compute(array_in, test_M)

        for idx in range(len(x_in)):
            x_out[idx] = array_in[idx]

    finally:
        PyMem_Free(test_M)

    return None

setup.py

import numpy
from Cython.Distutils import build_ext

def configuration(parent_package='', top_path=None):
    from numpy.distutils.misc_util import Configuration
    config = Configuration('', parent_package, top_path)
    config.add_extension('cython_param_test',
                         sources=['cython_param_test.pyx'],
                         # libraries=['m'],
                         depends=['ccodetest.c'],
                         include_dirs=[numpy.get_include()])
    return config


if __name__ == '__main__':
    params = configuration(top_path='').todict()
    params['cmdclass'] = dict(build_ext=build_ext)
    setup(**params)

run_cython_param_test.py

import cython_param_test
import numpy as np

n_samples = 4
x_in = np.arange(n_samples, dtype='double') % 4
x_out = np.empty((n_samples, 1))
gain = np.ones(1, dtype='double') * 5

cython_param_test.run(x_in, x_out, gain)

print(x_out)
Теги:
cython

1 ответ

0
Лучший ответ
cdef RT_MODEL_T* test_M = <RT_MODEL_T*> PyMem_Malloc(sizeof(RT_MODEL_T))

Вы выделяете место для RT_MODEL_T. test_M имеет один элемент, указатель на P_T. Выделение пространства для RT_MODEL_T выделяет пространство для хранения указателя - он не выделяет P_T на который указывает. Там, где param точки полностью произвольны в данный момент и, скорее всего, это адрес памяти, на который вам не разрешено писать.

test_M.param.gain_val = ...

Вы P_T записать элемент P_T на P_T указывает param. Однако param не указывает на выделенный P_T.

... = <double>gain

Вы пытаетесь сделать массив numpy двойным. Это не имеет никакого смысла. Вероятно, вы хотите получить первый элемент массива numpy, или вы должны передать gain как просто двойной, а не многомерный массив парных чисел?


Поскольку test_M и его содержимое не должны жить за пределами функции, в которую они выделены, у меня возникнет соблазн выделить их в стеке, и таким образом вы сможете полностью избежать malloc и free:

cdef RT_MODEL_T test_M # not a pointer
cdef P_T p_t_instance

p_t_instance.gain_val = gain # or gain[0]?

test_M.param = &p_t_instance

# ...
compute(array_in, &test_M) # pass the address of 'test_M'

Только делайте это, если вы уверены в требуемом времени жизни test_M и P_T котором есть указатель.

  • 0
    Спасибо за помощь, это сработало отлично.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню