我的 PyCFunction 第一次工作,但在连续迭代后导致段错误

无趣的猫

我想用 c 编写一个 python 对象,它包含一个 numpy 向量(实际上有两个,但在这个最小的例子中只有一个)。

首先,我只想创建一个带有 numpy 数组的对象,并看到我可以在循环中向所有数组元素添加一个。但即使这样也会导致奇怪的(可重现的)行为和段错误。

这是发生的事情(REPL):

from rletest import Rle
r = Rle(range(1, 10))
r.runs
# array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
r.add()
r.runs
# array([ 2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.])
r.add()
fish: 'python' terminated by signal SIGSEGV (Address boundary error)

我可以像这样解决这个问题:

... r2 = r.add()
>>> r3 = r2.add()
>>> r4 = r3.add()
>>> r4.runs
array([ 4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])

我怀疑这与引用计数有关?我对此完全是新手并且一无所知。任何帮助表示赞赏。这个函数(或我对它的使用)很可能是冒犯者:

static PyObject * Rle_add(Rle* self)
{
  int N = (int)PyArray_DIM(self->runs, 0);
  double *x = (double*)PyArray_DATA(self->runs);
  add(x, N);
  return (PyObject *)self;
}

它会就地更改数组以提高速度,但这不会导致错误,正如您从上面的解决方法中看到的那样。

下面是我的代码,所以这是可重现的。

我有以下文件:

test_rle.c:

#include <Python.h>
#include <numpy/arrayobject.h>
#include "structmember.h"
#include "add.h"

/* static PyObject *add(PyObject *self, PyObject *args); */

typedef struct {
    PyObject_HEAD
    PyObject *runs; /* run lengths */
} Rle;


static void
Rle_dealloc(Rle* self)
{
    Py_XDECREF(self->runs);
    Py_TYPE(self)->tp_free((PyObject*)self);
}


static PyObject *
Rle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{

  printf("New was called! New was called! New was called!\n");
    Rle *self;
    PyObject *rs, *vs;

    import_array();

    if (!PyArg_ParseTuple(args, "O", &rs))
      return NULL;

    PyObject *runs = PyArray_FROM_OTF(rs, NPY_DOUBLE, NPY_IN_ARRAY);

    self = (Rle *)type->tp_alloc(type, 0);
    if (self != NULL) {

        self->runs = runs;
        if (self->runs == NULL) {
            Py_DECREF(self);
            return NULL;
        }
    }

    printf("Reference count after new: %d\n", Py_REFCNT(self));
    return (PyObject *)self;
}

static int
Rle_init(Rle *self, PyObject *args, PyObject *kwds)
{
  printf("Init was called! Init was called! Init was called!\n");

  printf("Reference count after init: %d\n", Py_REFCNT(self));
    return 0;
}


static PyMemberDef Rle_members[] = {
    {"runs", T_OBJECT_EX, offsetof(Rle, runs), 0,
     "Run lengths"},
    {NULL}  /* Sentinel */
};

static PyObject * Rle_add(Rle* self)
{
  int N = (int)PyArray_DIM(self->runs, 0);
  double *x = (double*)PyArray_DATA(self->runs);
  add(x, N);
  return (PyObject *)self;
}


static PyMethodDef Rle_methods[] = {
    {"add", (PyCFunction)Rle_add, METH_NOARGS,
     "Add 1 to the runs"
    },
    {NULL}  /* Sentinel */
};

static PyTypeObject RleType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "rle.Rle",             /* tp_name */
    sizeof(Rle),             /* tp_basicsize */
    0,                         /* tp_itemsize */
    (destructor)Rle_dealloc, /* tp_dealloc */
    0,                         /* tp_print */
    0,                         /* tp_getattr */
    0,                         /* tp_setattr */
    0,                         /* tp_reserved */
    0,                         /* tp_repr */
    0,                         /* tp_as_number */
    0,                         /* tp_as_sequence */
    0,                         /* tp_as_mapping */
    0,                         /* tp_hash  */
    0,                         /* tp_call */
    0,                         /* tp_str */
    0,                         /* tp_getattro */
    0,                         /* tp_setattro */
    0,                         /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT |
        Py_TPFLAGS_BASETYPE,   /* tp_flags */
    "Rle objects",           /* tp_doc */
    0,                         /* tp_traverse */
    0,                         /* tp_clear */
    0,                         /* tp_richcompare */
    0,                         /* tp_weaklistoffset */
    0,                         /* tp_iter */
    0,                         /* tp_iternext */
    Rle_methods,             /* tp_methods */
    Rle_members,             /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)Rle_init,      /* tp_init */
    0,                         /* tp_alloc */
    Rle_new,                 /* tp_new */
};

static PyModuleDef rletestmodule = {
    PyModuleDef_HEAD_INIT,
    "rletest",
    "Example module that creates an extension type.",
    -1,
    NULL, NULL, NULL, NULL, NULL
};

PyMODINIT_FUNC
PyInit_rletest(void)
{
    PyObject* m;

    if (PyType_Ready(&RleType) < 0)
        return NULL;

    m = PyModule_Create(&rletestmodule);
    if (m == NULL)
        return NULL;

    Py_INCREF(&RleType);
    PyModule_AddObject(m, "Rle", (PyObject *)&RleType);
    return m;
}

设置.py:

from distutils.core import setup, Extension
setup(name="rle", version="1.0",
      ext_modules=[Extension("rletest", ["test_rle.c", "add.c"])])

添加.h

void add(double *x, int N);

添加.c:

#include <stdio.h>

void add(double *x, int N) {
  int n;

  for (n = 0; n < N; n++) {
    x[n] += 1.0;
  }
}

将它们全部放在同一个文件夹中并运行

python setup.py build_ext --inplace

来建造它。

大卫
return (PyObject *)self;

你现在有一个额外的参考,self所以你需要incref它。因为它是你不分配返回值所以 Python 立即decrefs它并r停止存在。

(您的解决方法避免了立即执行,decref但我很惊讶它稍后会导致分段错误。)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

是什么导致我的循环仅在第一次迭代中忽略此“ \ t”?

来自分类Dev

我正在尝试创建一个循环以在开罗中绘制多条线,但在第一次迭代后停止绘制

来自分类Dev

为什么我的循环只能在第一次迭代中正常工作?

来自分类Dev

我循环只经过第一次迭代

来自分类Dev

PyCFunction_New / PyCFunction_NewEx的文档

来自分类Dev

PyCFunction_New / PyCFunction_NewEx的文档

来自分类Dev

RecyclerView 在我第一次进入活动时没有填充,但在我退出并重新进入活动后显示

来自分类Dev

在 FormFlow Bot Framework 中第一次错误尝试后,我如何验证并提供选项列表

来自分类Dev

我在 r 中的 for 循环在第一次迭代时停止

来自分类Dev

为什么在我第一次在我的代码中插入一个项目后我的代码中出现分段错误

来自分类Dev

我如何在工作簿第一次打开时运行宏?

来自分类Dev

我如何在工作簿第一次打开时运行宏?

来自分类Dev

为什么我的客户端套接字在第一次发送后就死了?

来自分类Dev

为什么我的PXSmartPanel第一次执行后不能显示正确的数据?

来自分类Dev

第一次设置后,我似乎无法设置MKMapView批注标题

来自分类Dev

第一次获取我的@selector后如何获取非null的userInfo(方法)

来自分类Dev

为什么pgp在我使用--passphrase-fd后第一次询问密码

来自分类Dev

尝试递归问题(我第一次)

来自分类Dev

IE 8不想让我第一次下载

来自分类Dev

我第一次使用 PHPMailer

来自分类Dev

尝试安装 Ubuntu 18.04.2 双启动,它第一次工作,一旦我重新启动它就不再启动,“PCIe 总线”错误

来自分类Dev

在Android Studio上运行我的第一次自动生成的代码会给我一个错误

来自分类Dev

为什么setTimeout()第一次只运行一次我的代码?

来自分类Dev

在iOS上重置模拟器后,我第一次运行黄瓜应用程序崩溃

来自分类Dev

我的脚本第一次运行,在这个在线 IDE 上重新加载后不再运行

来自分类Dev

仅当我向下滚动页面时,可排序的 JQuery 元素在第一次拖动后从光标偏移

来自分类Dev

html界面在第一次使用后消失,并向我抛出一些错误

来自分类Dev

我的 javascript 单击事件在第二次单击时运行,但在第一次单击时不运行

来自分类Dev

为什么在使用 node 和 redis 时我的承诺没有解决?我的数组返回第一次迭代而不是等待整个代码运行

Related 相关文章

  1. 1

    是什么导致我的循环仅在第一次迭代中忽略此“ \ t”?

  2. 2

    我正在尝试创建一个循环以在开罗中绘制多条线,但在第一次迭代后停止绘制

  3. 3

    为什么我的循环只能在第一次迭代中正常工作?

  4. 4

    我循环只经过第一次迭代

  5. 5

    PyCFunction_New / PyCFunction_NewEx的文档

  6. 6

    PyCFunction_New / PyCFunction_NewEx的文档

  7. 7

    RecyclerView 在我第一次进入活动时没有填充,但在我退出并重新进入活动后显示

  8. 8

    在 FormFlow Bot Framework 中第一次错误尝试后,我如何验证并提供选项列表

  9. 9

    我在 r 中的 for 循环在第一次迭代时停止

  10. 10

    为什么在我第一次在我的代码中插入一个项目后我的代码中出现分段错误

  11. 11

    我如何在工作簿第一次打开时运行宏?

  12. 12

    我如何在工作簿第一次打开时运行宏?

  13. 13

    为什么我的客户端套接字在第一次发送后就死了?

  14. 14

    为什么我的PXSmartPanel第一次执行后不能显示正确的数据?

  15. 15

    第一次设置后,我似乎无法设置MKMapView批注标题

  16. 16

    第一次获取我的@selector后如何获取非null的userInfo(方法)

  17. 17

    为什么pgp在我使用--passphrase-fd后第一次询问密码

  18. 18

    尝试递归问题(我第一次)

  19. 19

    IE 8不想让我第一次下载

  20. 20

    我第一次使用 PHPMailer

  21. 21

    尝试安装 Ubuntu 18.04.2 双启动,它第一次工作,一旦我重新启动它就不再启动,“PCIe 总线”错误

  22. 22

    在Android Studio上运行我的第一次自动生成的代码会给我一个错误

  23. 23

    为什么setTimeout()第一次只运行一次我的代码?

  24. 24

    在iOS上重置模拟器后,我第一次运行黄瓜应用程序崩溃

  25. 25

    我的脚本第一次运行,在这个在线 IDE 上重新加载后不再运行

  26. 26

    仅当我向下滚动页面时,可排序的 JQuery 元素在第一次拖动后从光标偏移

  27. 27

    html界面在第一次使用后消失,并向我抛出一些错误

  28. 28

    我的 javascript 单击事件在第二次单击时运行,但在第一次单击时不运行

  29. 29

    为什么在使用 node 和 redis 时我的承诺没有解决?我的数组返回第一次迭代而不是等待整个代码运行

热门标签

归档