尝试写入C扩展中创建的Numpy数组时出现SegFault [英] SegFault when trying to write to a Numpy array created within a C Extension

查看:100
本文介绍了尝试写入C扩展中创建的Numpy数组时出现SegFault的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在for循环中有一个if子句,其中我预先定义了state_out:

I have an if clause within a for loop in which I have defined state_out beforehand with:

state_out = (PyArrayObject *) PyArray_FromDims(1,dims_new,NPY_BOOL);

if条件如下:

        if (conn_ctr<sum*2){
            *(state_out->data + i*state_out->strides[0]) =  true;
        }
        else {
            *(state_out->data + i*state_out->strides[0]) =  false;
        }

在注释掉这些内容时,state_out返回为全错误的Numpy数组.我看不到此作业存在一个问题.据我所知,在此代码中在此调用的struct PyArrayObject结构中,所有指针都是指针,因此在指针算术之后,它应该指向我打算编写的地址. (如果代码中的条件都是通过以这种方式达到值而建立的,并且我知道它是可行的,因为我设法打印了输入数组的值.)然后,如果我想给内存中的这些部分之一分配一个布尔值,我应该通过*(pointer_intended) = true进行分配?

When commenting these out, state_out returns as an all-False Numpy array. There is a problem with this assignment that I fail to see. As far as I know, all within the struct PyArrayObject that are called here in this code are pointers, so after the pointer arithmetic, it should be pointing to the address I intend to write. (All if conditions in the code are built by reaching values in this manner, and I know it works, since I managed to printf input arrays' values.) Then if I want to assign a bool to one of these parts in the memory, I should assign it via *(pointer_intended) = true What am I missing?

我发现即使我在其中放了一些printf函数,也达不到这些值:

I have spotted that even if I don't reach those values even if I put some printf functions within:

if (conn_ctr<sum*2){
    printf("True!\n");
}
else {
    printf("False!\n");
}

我再次遇到了SegFault.

I get a SegFault again.

非常感谢,其余的代码在这里.

Thanks a lot, an the rest of the code is here.

#include <Python.h>
#include "numpy/arrayobject.h"
#include <stdio.h>
#include <stdbool.h>

static PyObject* trace(PyObject *self, PyObject *args);

static char doc[] =
"This is the C extension for xor_masking routine. It interfaces with Python via C-Api, and calculates the"
"next state with C pointer arithmetic";

static PyMethodDef TraceMethods[] = {
    {"trace", trace, METH_VARARGS, doc},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
inittrace(void)
{
    (void) Py_InitModule("trace", TraceMethods);
    import_array();
}

static PyObject* trace(PyObject *self, PyObject *args){
    PyObject *adjacency ,*mask, *state;
    PyArrayObject *adjacency_arr, *mask_arr, *state_arr, *state_out;

    if (!PyArg_ParseTuple(args,"OOO:trace", &adjacency, &mask, &state)) return NULL;

    adjacency_arr = (PyArrayObject *)
        PyArray_ContiguousFromObject(adjacency, NPY_BOOL,2,2);

    if (adjacency_arr == NULL) return NULL;
    mask_arr = (PyArrayObject *)
        PyArray_ContiguousFromObject(mask, NPY_BOOL,2,2);

    if (mask_arr == NULL) return NULL;
    state_arr = (PyArrayObject *)
        PyArray_ContiguousFromObject(state, NPY_BOOL,1,1);

    if (state_arr == NULL) return NULL;

    int dims[2], dims_new[1];
    dims[0] = adjacency_arr -> dimensions[0];
    dims[1] = adjacency_arr -> dimensions[1];
    dims_new[0] =  adjacency_arr -> dimensions[0];
    if (!(dims[0]==dims[1] && mask_arr -> dimensions[0] == dims[0]
                         && mask_arr -> dimensions[1] == dims[0]
                         && state_arr -> dimensions[0] == dims[0]))
                         return NULL;


    state_out = (PyArrayObject *) PyArray_FromDims(1,dims_new,NPY_BOOL);

    int i,j;

    for(i=0;i<dims[0];i++){
        int sum = 0;
        int conn_ctr = 0;

            for(j=0;j<dims[1];j++){

                bool adj_value = (adjacency_arr->data + i*adjacency_arr->strides[0]
                         +j*adjacency_arr->strides[1]);

                if (*(bool *) adj_value == true){

                    bool mask_value = (mask_arr->data + i*mask_arr->strides[0]
                    +j*mask_arr->strides[1]);
                    bool state_value = (state_arr->data + j*state_arr->strides[0]);

                    if ( (*(bool *) mask_value ^ *(bool *)state_value) ==  true){
                        sum++;
                    }
                    conn_ctr++;
                }
            }

            if (conn_ctr<sum*2){

            }
            else {

            }
    }

    Py_DECREF(adjacency_arr);
    Py_DECREF(mask_arr);
    Py_DECREF(state_arr);
    return PyArray_Return(state_out);
}

推荐答案

    if (conn_ctr<sum*2){
        *(state_out->data + i*state_out->strides[0]) =  true;
    }
    else {
        *(state_out->data + i*state_out->strides[0]) =  false;
    }

在这里,我天真地做了一个指针算术,state_out-> data是指向数据开头的指针,它被定义为char的指针:

Here, I naively make a pointer arithmetic, state_out->data is a pointer to the beginning of data, it is defined to be a pointer of char:SciPy Doc - Python Types and C-Structures

typedef struct PyArrayObject {
    PyObject_HEAD
    char *data;
    int nd;
    npy_intp *dimensions;
    npy_intp *strides;
    ...
} PyArrayObject;

我的其中一部分抄录在这里. state_out-> strides是一个指向数组长度的指针,该数组的长度与我们拥有的数组的维数相同.在这种情况下,这是一维数组.因此,当我对指针进行算术运算(state_out->data + i*state_out->strides[0])时,我当然旨在计算指向数组第i个值的指针,但是我无法给出指针的类型,因此

Which a portion of I copied here. state_out->strides is a pointer to an array of length of the dimension of the array we have. This is a 1d array in this case. So when I make the pointer arithmetic (state_out->data + i*state_out->strides[0]) I certainly aim to calculate the pointer that points the ith value of the array, but I failed to give the type of the pointer, so the

我尝试过:

NPY_BOOL *adj_value_ptr, *mask_value_ptr, *state_value_ptr, *state_out_ptr;

其中的变量指向我对我的for循环感兴趣的值,而state_out_ptr是我正在写入的值.我一直以为,自从我声明 这些数组的组成部分的类型为NPY_BOOL,指向数组中数据的指针也将为类型NPY_BOOL. 当使用数据直接操作内存时,SegFault会失败.这是因为NPY_BOOL是整数的enum(如pv友好地在注释中所述.),供NumPy在内部使用.为了在代码中使用C typedef npy_bool,需要使用C typedef npy_bool.布尔值. Scipy Docs .当我介绍类型为

which the variables are pointing towards the values that I am interested in my for loop, and state_out_ptr is the one that I am writing to. I had thought that since I state that the constituents of these arrays are of type NPY_BOOL, the pointers that point to the data within the array would be of type NPY_BOOL also. This fails with a SegFault when one is working with data directly manipulating the memory. This is from the fact that NPY_BOOL is an enum for an integer (as pv kindly stated in the comments.) for NumPy to use internally,.There is a C typedef npy_bool in order to use within the code for boolean values. Scipy Docs. When I introduced my pointers with the type

npy_bool *adj_value_ptr, *mask_value_ptr, *state_value_ptr, *state_out_ptr;

分段错误消失了,我成功地操作并返回了一个Numpy数组.

Segmentation fault disappeared, and I succeeded in manipulating and returning a Numpy Array.

我不是专家,但这解决了我的问题,并指出我是否错了.

I'm not an expert, but this solved my issue, point out if I'm wrong.

源代码中已更改的部分是:

The part that has changed in the source code is:

state_out = (PyArrayObject *) PyArray_FromDims(1,dims_new,NPY_BOOL);

npy_bool *adj_value_ptr, *mask_value_ptr, *state_value_ptr, *state_out_ptr;
npy_intp i,j;

for(i=0;i<dims[0];i++){
    npy_int sum = 0;
    npy_int conn_ctr = 0;

        for(j=0;j<dims[1];j++){

            adj_value_ptr = (adjacency_arr->data + i*adjacency_arr->strides[0]
                     +j*adjacency_arr->strides[1]);

            if (*adj_value_ptr == true){

                mask_value_ptr = (mask_arr->data + i*mask_arr->strides[0]
                +j*mask_arr->strides[1]);

                state_value_ptr = (state_arr->data + j*state_arr->strides[0]);

                if ( (*(bool *) mask_value_ptr ^ *(bool *)state_value_ptr) ==  true){
                    sum++;
                }
                conn_ctr++;
            }
        }
        state_out_ptr = (state_out->data + i*state_out->strides[0]);
        if (conn_ctr < sum*2){
            *state_out_ptr =  true;
        }
        else {
            *state_out_ptr =  false;
        }
}

这篇关于尝试写入C扩展中创建的Numpy数组时出现SegFault的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆