1

I created a small C wrapper function which requires two bytes variables:

static PyObject * wrapperfunction(PyObject * self, PyObject * args) {
    const unsigned char * data;
    Py_ssize_t datalen;
    const unsigned char * otherdata;
    Py_ssize_t otherlen;

    if (!PyArg_ParseTuple(args, "y#y#", &data, &datalen, &otherdata, &otherlen))
        return NULL;

    some_function(data, datalen, otherdata, otherlen);
}

But I noticed that on Linux 64bit the function would fail in certain cases (I could not really narrow them down to a special case) and segfault inside some_function as data was a not readable address. usually this address would be 0x7fff00000001

I would not see why this was happening but changed the code to use Py_buffer instead - which works perfectly:

static PyObject * wrapperfunction(PyObject * self, PyObject * args) {
    Py_buffer data;
    Py_buffer otherdata;

    if (!PyArg_ParseTuple(args, "y*y*", &data, &otherdata))
        return NULL;

    some_function((unsigned char *)data.buf, data.len, (unsigned char *)otherdata, otherdata.len);
}

As far as I can tell, the python documentation only says that y* is the preferred method, but not that y# would only work once. Is there any reason why the method using y# fails?

I'm using Python 3.5.3 on debian stretch amd64. On a Windows machine (python 3.6.4 / x64), the same code never produced a segfault.

reox
  • 5,036
  • 11
  • 53
  • 98
  • The only obvious thing I can see is that you define the two numbers as `Py_ssize_t` but the [documentation](https://docs.python.org/3/c-api/arg.html) implies that they should be `int`. I don't know that two types are guaranteed to be the same. – DavidW Mar 13 '19 at 14:20
  • 1
    Py_ssize_t is fine if you define `PY_SSIZE_T_CLEAN` (which I did): "This behavior will change in a future Python version to only support Py_ssize_t and drop int support. It is best to always define PY_SSIZE_T_CLEAN." – reox Mar 13 '19 at 14:25

0 Answers0