`PyTuple_Pack` segfault

谁说胖子不能爱 提交于 2021-01-20 04:57:07

问题


I have a function foo in a Python Extension Module that should return a tuple of ints to Python. This can be easily done using Py_BuildValue:

static PyObject* 
foo(PyObject* self, PyObject* args)
{
    int a = 0;
    int b = 0;

    /* calculations and stuff */

    PyObject* out = Py_BuildValue("(iii)", a, b, a+b);
    Py_INCREF(out);

    return out;
}

Instead of Py_BuildValue, I want to use PyTuple_Pack, which ensures that the return value is indeed a tuple.

The Python C API documentation says that PyTuple_Pack(3, a, b, a+b) is equivalent to Py_BuildValue("(iii)", a, b, a+b). Both functions return a new reference of type PyPbject*.

Hence, given the code above,

static PyObject* 
foo(PyObject* self, PyObject* args)
{
    /* ... */

    PyObject* out = PyTuple_Pack(3, a, b, a+b);
    Py_INCREF(out);

    return out;
}

should do the trick, which is does not. Instead I get a segfault. What am I missing here?


回答1:


The difference is:

  • Py_BuildValue("(ii)", a, b) expects a and b to be simple C-int values.
  • PyTuple_Pack(2, a, b) expects a and b to be already PyObjects (and not C-ints).

The documentation says:

The tuple values are initialized to the subsequent n C arguments pointing to Python objects. PyTuple_Pack(2, a, b) is equivalent to Py_BuildValue("(OO)", a, b).

In order to use PyTuple_Pack you need to convert the int-values to Python-Integers first.

It is simpler to use Py_BuildValue(). If you parenthesize your format string in Py_BuildValue, the result will be a tuple:

Py_BuildValue() does not always build a tuple. It builds a tuple only if its format string contains two or more format units. If the format string is empty, it returns None; if it contains exactly one format unit, it returns whatever object is described by that format unit. To force it to return a tuple of size 0 or one, parenthesize the format string.

That means: there is nothing to worry about if you construct a tuple from at least two elements:

Py_BuildValue("ii", a, b)   # returns a tuple
Py_BuildValue("(ii)", a, b) # returns a tuple

It is different if there is only one element:

Py_BuildValue("i", a)    # returns an integer
# parenthesized:
Py_BuildValue("(i)", a)  # returns a tuple with an integer

or no elements at all:

Py_BuildValue("")    # returns None
# parenthesized:
Py_BuildValue("()")  # returns an empty tuple.

So just make sure there are parenthesizes in the format string and the returned value will be a tuple.



来源:https://stackoverflow.com/questions/52179761/pytuple-pack-segfault

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!