Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
单线程C程序中Py_Finalize(python 2.5)处的Segfault_Python_C_Segmentation Fault_Cpython - Fatal编程技术网

单线程C程序中Py_Finalize(python 2.5)处的Segfault

单线程C程序中Py_Finalize(python 2.5)处的Segfault,python,c,segmentation-fault,cpython,Python,C,Segmentation Fault,Cpython,在下面的hello world C程序中,我扩展并嵌入了Python spam.c: #include <Python.h> static PyObject * spam_echo(PyObject *self, PyObject *args) { const char *command; int sts; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; st

在下面的hello world C程序中,我扩展并嵌入了Python

spam.c

#include <Python.h>

static PyObject *
spam_echo(PyObject *self, PyObject *args) {
    const char *command;
    int sts;

    if (!PyArg_ParseTuple(args, "s", &command))
        return NULL;
    sts = printf("%s\n", command);
    return Py_BuildValue("i", sts);
}

static PyMethodDef SpamMethods[] = {
    {"echo", spam_echo, METH_VARARGS, "Prints passed argument"},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initspam(void) {
    (void) Py_InitModule("spam", SpamMethods);
}

int main(int argc, char *argv[]) {
    PyObject *args;
    PyObject *arg;
    PyObject *result;
    PyObject *moduleName;
    PyObject *module;
    PyObject *func;

    Py_SetProgramName(argv[0]);
    Py_Initialize();
    initspam();

    PyRun_SimpleFile(fopen("foo.py", "r"), "foo.py");

    moduleName = PyString_FromString("__main__");
    module = PyImport_Import(moduleName);
    Py_DECREF(moduleName);
    if (!module) {
        return 1;
    }

    func = PyObject_GetAttrString(module, "foo");
    Py_DECREF(module);
    if (!func || !PyCallable_Check(func)) {
        return 1;
    }

    args = PyTuple_New(1);
    arg = Py_BuildValue("s", "hello world");
    PyTuple_SetItem(args, 0, arg);

    result = PyObject_CallObject(func, args);
    Py_DECREF(arg);
    Py_DECREF(args);
    Py_DECREF(func);

    printf("== before\n");
    Py_Finalize();
    printf("== after\n");
}
#!/usr/bin/python

import spam

def foo(cmd):
    spam.echo(cmd)
我用

gcc spam.c -I/usr/include/python2.5/ -lpython2.5
使用GCC4.2.4-1ubuntu4,我在Ubuntu Hardy上使用python2.5-dev包

基本上,我在Py_Finalize上有一个segfault,如输出所示:

hello world
== before
Segmentation fault

交换行
Py_DECREF(args)
Py_DECREF(arg)解决了这个问题。segfault是在它被释放后从
Py_DECREF(args)
访问
arg的结果。

也许将行替换为Python2修复了它,但它不应该,当然也不会为Python3修复。请再次查看代码段:

args = PyTuple_New(1);
arg = Py_BuildValue("s", "hello world");
PyTuple_SetItem(args, 0, arg);
PyTuple\u New
创建一个新对象,就像
Py\u BuildValue
一样。如果你在那里停下来,是的,你应该两个都减少

但是,
PyTuple\u SetItem(args,0,arg)
窃取了
arg
的引用。这意味着
arg
现在由元组
args
拥有。您不再负责
arg
,因此不应减少它的值

args
为DECREF时,它将对其每个项目进行DECREF,这将处理
arg
。(如果愿意,请使用
Py_REFCNT()
)进行验证

这意味着,例如,如果要将
arg
放入两个列表中,则需要增加一次:

args1 = PyTuple_New(1);
args2 = PyTyple_New(1);
arg = Py_BuildValue("s", "hello world");
PyTuple_SetItem(args1, 0, arg);
PyTyple_SetItem(args2, 0, arg);
Py_INCREF(arg);
因此,当删除
args1
时,它可以将arg减一次,而不会导致args2出现问题


注意,创建后,您可以在任何地方增加(arg),即使在SetItem之后也是如此——它仍然在范围内。

我实际上刚刚找到了导致segfault的原因!我必须注释掉
Py\u DECREF(arg)
Py\u DECREF(args)
。我的猜测是,递减
arg
也会自动递减
arg
,因此我会递减
arg
两次。我仍然需要确认或其他人的解释!非常感谢!那有帮助!