为什么我在 C 扩展方法声明中收到段错误?

问题描述 投票:0回答:0

我正在尝试为我实现的 Python 的 C 扩展类型创建

__reduce__
方法,因此它变成了
pickable
。我已经用其他类型完成了,但由于某种原因,在这种情况下我收到了段错误。

这是最小的可复制示例:

main.c

#define PY_SSIZE_T_CLEAN
#include <Python.h>

typedef struct
{
    PyObject_HEAD unsigned char attr1;
    unsigned char attr2;
    unsigned char attr3;
} SomeObject;

static int SomeObject__init(SomeObject *self, PyObject *args, PyObject *kwds)
{
    static char *kwlist[] = {"attr1", "attr2", "attr3", NULL};
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "bbb", kwlist, &self->attr1,
                                     &self->attr2, &self->attr3))
    {
        return -1;
    }

    return 0;
}

static PyObject *SomeObject__reduce(SomeObject *self, PyObject *Py_UNUSED(ignored))
{
    return Py_BuildValue("O(BBB)N", Py_TYPE(self), self->attr1, self->attr2, self->attr3,
                         Py_None);
}

static PyMethodDef SomeObject__methods[] = {
    {
        .ml_name = "__reduce__",
        .ml_meth = (PyCFunction)SomeObject__reduce,
        .ml_flags = METH_NOARGS,
    },
};

static PyTypeObject SomeType = {
    PyVarObject_HEAD_INIT(NULL, 0)
        .tp_name = "somemodule.SomeObject",
    .tp_basicsize = sizeof(SomeObject),
    .tp_itemsize = 0,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_methods = SomeObject__methods,
    .tp_init = (initproc)SomeObject__init,
    .tp_new = PyType_GenericNew,
};

static PyModuleDef somemodule = {
    PyModuleDef_HEAD_INIT,
    .m_name = "somemodule",
    .m_size = -1,
};

PyMODINIT_FUNC
PyInit_somemodule(void)
{
    if (PyType_Ready(&SomeType) < 0)
        return NULL;

    PyObject *m = PyModule_Create(&somemodule);
    if (m == NULL)
        return NULL;

    Py_INCREF(&SomeType);
    if (PyModule_AddObject(m, "Some", (PyObject *)&SomeType) < 0)
    {
        Py_DECREF(&SomeType);
        Py_DECREF(m);
        return NULL;
    }

    return m;
}

setup.py

from setuptools import setup, Extension

setup(
    name="somemodule",
    version="0.1.0",
    ext_modules=[Extension("somemodule", ["main.c"])]
)

演示.py

import somemodule
somemodule.Some(12, 12, 12).__reduce__()

这里是 GDB 输出和回溯:

GDB 输出

$ gdb /home/xlurio/Playground/minimum-SIGSEGV/venv/bin/python -ex "run \"/home/xlurio/Playground/minimum-SIGSEGV/demo.py\""
Program received signal SIGSEGV, Segmentation fault.
0x000000000058da02 in PyUnicode_FromFormatV ()
(gdb) bt
#0  0x000000000058da02 in PyUnicode_FromFormatV ()
#1  0x000000000055cbaf in PyErr_Format ()
#2  0x00000000004d2924 in ?? ()
#3  0x00007ffff7fbe252 in PyInit_somemodule () at main.c:57
#4  0x0000000000685b4e in _PyImport_LoadDynamicModuleWithSpec ()
#5  0x0000000000686661 in ?? ()
#6  0x00000000005c52f0 in ?? ()
#7  0x00000000005f61c8 in PyVectorcall_Call ()
--Type <RET> for more, q to quit, c to continue without paging--
#8  0x0000000000571917 in _PyEval_EvalFrameDefault ()
#9  0x0000000000569cea in _PyEval_EvalCodeWithName ()
#10 0x00000000005f6a13 in _PyFunction_Vectorcall ()
#11 0x0000000000570ac2 in _PyEval_EvalFrameDefault ()
#12 0x00000000005f6836 in _PyFunction_Vectorcall ()
#13 0x000000000056bbdf in _PyEval_EvalFrameDefault ()
#14 0x00000000005f6836 in _PyFunction_Vectorcall ()
#15 0x000000000056b9fd in _PyEval_EvalFrameDefault ()
--Type <RET> for more, q to quit, c to continue without paging--
#16 0x00000000005f6836 in _PyFunction_Vectorcall ()
#17 0x000000000056b9fd in _PyEval_EvalFrameDefault ()
#18 0x00000000005f6836 in _PyFunction_Vectorcall ()
#19 0x000000000056b9fd in _PyEval_EvalFrameDefault ()
#20 0x00000000005f6836 in _PyFunction_Vectorcall ()
#21 0x00000000005f3c41 in ?? ()
#22 0x00000000005f40a8 in _PyObject_CallMethodIdObjArgs ()
#23 0x0000000000552f1c in PyImport_ImportModuleLevelObject ()
--Type <RET> for more, q to quit, c to continue without paging--
#24 0x000000000056ddd5 in _PyEval_EvalFrameDefault ()
#25 0x0000000000569cea in _PyEval_EvalCodeWithName ()
#26 0x000000000068e7b7 in PyEval_EvalCode ()
#27 0x0000000000680001 in ?? ()
#28 0x000000000068007f in ?? ()
#29 0x0000000000680121 in ?? ()
#30 0x0000000000680db7 in PyRun_SimpleFileExFlags ()
#31 0x00000000006b8122 in Py_RunMain ()
--Type <RET> for more, q to quit, c to continue without paging--
#32 0x00000000006b84ad in Py_BytesMain ()
#33 0x00007ffff7de4083 in __libc_start_main (main=0x4ef1e0 <main>, argc=2, argv=0x7fffffffd998, init=<optimized out>, 
    fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd988) at ../csu/libc-start.c:308
#34 0x00000000005fb39e in _start ()
python c ctypes
© www.soinside.com 2019 - 2024. All rights reserved.