我正在尝试使用pythoncapi实现一个简单的生成器。生成器功能正在工作,但是python解释器(或其他东西)在调用Py_TYPE(self)->tp_free((PyObject*)self)
期间出错了。我已经读了又读了引用文档,并且认为引用计数正确,但是SIGSEGV仍然存在。我已经用调试符号构建了扩展,并用gdb(下面的输出)进行了调试,它似乎正在解释器中发生。我所知道的唯一一件我还没有尝试过的事情是从源代码构建带有调试符号的python,以允许进一步的自省。任何帮助或正确的文件点将不胜感激。我使用的是python3.6.4
#include "hexc.h"
// Define class boilerplate functions
static PyObject *hex_range_iter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
hexrangeiter_t *self;
self = (hexrangeiter_t *)(type->tp_alloc(type, 0));
if (self != NULL) {
self->pos = 0;
self->dir = 0;
self->distance = 1;
self->radius = 0;
self->hex = NULL;
self->center = NULL;
}
return (PyObject *)self;
}
static void hex_range_iter_dealloc(hexrangeiter_t *self)
{
Py_DECREF(self->hex); // decref our stored hex
Py_DECREF(self->center); // and our center point
Py_TYPE(self)->tp_free((PyObject*)self); // SIGSEGV here
}
static int hex_range_iter_init(hexrangeiter_t *self, PyObject *args, PyObject *kwds)
{
// Takes 2 args, the center of the ring as an AbstractHex, and the radius as an int
static char *kwlist[] = {"center", "radius", NULL};
if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &self->center, &self->radius))
return -1;
Py_INCREF(self->center); //increc\f here because Py_Arg_Parse... returns borrowed references
PyObject *radius = PyLong_FromLong(1L);
PyObject *direction = PyObject_CallMethod(self->center, "direction", "i", 4);
PyObject *scaled = PyNumber_Multiply(direction, radius);
self->hex = PyNumber_Add(self->center, scaled); // No incref needed because Py_Number_Add returns a new reference
Py_DECREF(radius); // decref all of our temp variables
Py_DECREF(direction);
Py_DECREF(scaled);
return 0;
}
static PyObject *hex_range_iter_next(hexrangeiter_t *self)
{
self->pos++; // pos is the index along a side of a hexagonal ring
if (self->pos >= self->radius) // its length is equal to the radius of the ring
{ // so check if we've run off the end and if so change direction
self->pos = 0;
self->dir++;
}
if (self->dir >= 6) // If we've already done all 6 sides
{
self->dir = 0; // reset our direction
self->distance++; // and increase our radius
if (self->distance >= self->radius) // If we've reached our max radius
return NULL; // return NULL to exit generator
// Returning NULL in this case is enough. The next() builtin will raise the
// StopIteration error for us.
PyObject *radius = PyLong_FromLong(self->distance); // calculate our new starting position v
PyObject *direction = PyObject_CallMethod(self->center, "direction", "i", 4);
PyObject *scaled = PyNumber_Multiply(direction, radius);
Py_DECREF(self->hex); // make sure to decref our unused hex from last call
self->hex = PyNumber_Add(self->center, scaled); // finish calc and save new hex ^
Py_DECREF(radius); // decref all our temp variables
Py_DECREF(direction);
Py_DECREF(scaled);
}
PyObject *ret = self->hex; // grab a ref to our return value
self->hex = PyObject_CallMethod(ret, "neighbor", "i", self->dir); // store the next hex in our sequence
return (ret);
}
PyTypeObject HexRangeGenType = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"HexRangeGenerator", /* tp_name */
sizeof(hexrangeiter_t), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)hex_range_iter_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, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)hex_range_iter_next, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)hex_range_iter_init, /* tp_init */
0, /* tp_alloc */
hex_range_iter_new, /* tp_new */
};
十六进制c
#ifndef HEXC_H
#define HEXC_H
#include <Python.h>
#include <structmember.h>
#include <stdlib.h>
// #include "math_3d.h"
// declare Hex object structure
struct abstracthex_s;
struct hex_s;
struct slice_s;
struct stack_s;
struct grid_s;
struct hexringiter_s;
struct hexrangeiter_s;
typedef struct abstracthex_s abstracthex_t;
typedef struct slice_s slice_t;
typedef struct stack_s stack_t;
typedef struct hex_s hex_t;
typedef struct grid_s grid_t;
typedef struct hexringiter_s hexringiter_t;
typedef struct hexrangeiter_s hexrangeiter_t;
struct abstracthex_s
{
PyObject_HEAD
int q;
int r;
int s;
};
struct hexringiter_s
{
PyObject_HEAD
int pos;
int dir;
int radius;
PyObject *hex;
};
struct hexrangeiter_s
{
PyObject_HEAD
int dir;
long pos;
long distance;
long radius;
PyObject *hex;
PyObject *center;
};
// declare Python type objects
extern PyTypeObject AbstractHexType;
extern PyTypeObject HexRingGenType;
extern PyTypeObject HexRangeGenType;
extern PyTypeObject HexType;
extern PyTypeObject SliceType;
extern PyTypeObject StackType;
extern PyTypeObject GridType;
// declare some handy constants
static int DIRECTIONS[6][3] = {
{1, 0, -1},
{1, -1, 0},
{0, -1, 1},
{-1, 0, 1},
{-1, 1, 0},
{0, 1, -1}
};
#endif
你知道吗测试.py你知道吗
import hexc
import time
center = hexc.AbstractHex(0,0,0)
start = time.time()
z = 0
for hex in hexc.HexRangeGenerator(center, 5):
z += 1
print(time.time() - start)
gdb堆栈跟踪
#0 0x0000000000000000 in ?? ()
#1 0x00007ffff67ce521 in hex_range_iter_dealloc (self=0x7ffff6a0f5f0) at hexc/hex_range_iter.c:28
#2 0x00007ffff73c2e05 in _PyEval_EvalFrameDefault () from /usr/lib/libpython3.6m.so.1.0
#3 0x00007ffff742b2c8 in PyEval_EvalCodeEx () from /usr/lib/libpython3.6m.so.1.0
#4 0x00007ffff73be6ec in PyEval_EvalCode () from /usr/lib/libpython3.6m.so.1.0
#5 0x00007ffff7490f84 in ?? () from /usr/lib/libpython3.6m.so.1.0
#6 0x00007ffff7493751 in PyRun_FileExFlags () from /usr/lib/libpython3.6m.so.1.0
#7 0x00007ffff7493954 in PyRun_SimpleFileExFlags () from /usr/lib/libpython3.6m.so.1.0
#8 0x00007ffff748970b in Py_Main () from /usr/lib/libpython3.6m.so.1.0
#9 0x0000555555554c39 in main ()
这个问题与参考文献计数无关(我想)
在将类型添加到模块时,我犯了一个错误。你知道吗
if (PyType_Ready(&HexRingGenType) < 0)
return NULL;
应该是的
if (PyType_Ready(&HexRangeGenType) < 0)
return NULL
修复此问题导致故障消失。你知道吗
正如暗影游侠在评论中所指出的,我在引用计数方面也犯了错误
目前没有回答
相关问题 更多 >
编程相关推荐