【问题标题】:Segfault at Py_Finalize (python 2.5) in single threaded C program单线程 C 程序中 Py_Finalize (python 2.5) 的段错误
【发布时间】:2012-12-23 02:43:04
【问题描述】:

在下面这个 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");
}

这里是调用的 Python 程序:

foo.py

#!/usr/bin/python

import spam

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

我用编译

gcc spam.c -I/usr/include/python2.5/ -lpython2.5

使用 GCC 4.2.4-1ubuntu4,我在 Ubuntu Hardy 上使用 python2.5-dev 包。

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

hello world
== before
Segmentation fault

【问题讨论】:

  • 我实际上刚刚找到了导致段错误的原因!我必须注释掉Py_DECREF(arg)Py_DECREF(args)。我的猜测是去引用args 也会自动去引用arg,所以我会去引用arg 两次。我仍然需要某人的确认或其他解释!

标签: python c segmentation-fault cpython


【解决方案1】:

交换Py_DECREF(args);Py_DECREF(arg); 行可以解决问题。段错误是从Py_DECREF(args) 访问arg 在它已经被释放之后的结果。

【讨论】:

  • 非常感谢!这有帮助!
【解决方案2】:

也许换行解决了 Python2 的问题,但它不应该有,当然也不会适用于 Python 3。再看看 sn-p:

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

PyTuple_New 创建一个新对象,Py_BuildValue 也是如此。如果你停在那里,是的,你应该 DECREF 两者。

但是,PyTuple_SetItem(args, 0, arg) 窃取了 arg 的引用。这意味着arg 现在由元组args“拥有”。您不再对 arg 负责,因此不应 DECREF它。

args 是 DECREF 时,它将 DECREF 其每个项目,这将照顾 arg。 (如果您愿意,请使用Py_REFCNT())进行验证。

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

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 被移除时,它可以DECREF arg 一次,而不会导致args2 出现问题。

请注意,您可以在创建后的任何位置进行 INCREF(arg),即使在 SetItem 之后 - 它仍在范围内。

【讨论】:

    猜你喜欢
    • 2014-08-15
    • 1970-01-01
    • 2014-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    • 1970-01-01
    • 2012-06-09
    相关资源
    最近更新 更多