0

I am trying to overload the following sayHi function, that is meant to receive a char* as input argument, or, alternatively, a char* and an integer.

It is part of class Box (which itself is used to define the python object PyBox):

class Box {
   public:

   Box();

   void sayHi(char *name);

   void sayHi(char *name, int number);
   };

In my wrapper, I have defined the following methods:

static PyObject *pyBox_sayHi_char(PyBox *self, char *Name)
{
    self->bx->sayHi(Name);

    Py_RETURN_NONE;
}

static PyObject *pyBox_sayHi_char_int(PyBox *self, char *Name, int number)
{
        self->bx->sayHi(Name, number);

    Py_RETURN_NONE;
}

static PyObject *Hi_overload_switch(PyBox *self,  PyObject *args)
{
    PyObject *x = NULL;
    PyObject *y = NULL;

    if (!PyArg_ParseTuple(args, "|OO", &x, &y))
        return NULL;

    if (PyUnicode_Check(x) && PyLong_Check(y) && y != NULL)
    {
        printf("A!\n\n");

        const char* s = PyBytes_AsString(PyUnicode_AsUTF8String(x)); 

        Py_DECREF(x);

        return pyBox_sayHi_char_int(self, s, PyLong_AsLong(y));

    }
    else if (PyUnicode_Check(x) && y == NULL)
    {   
        printf("B!\n\n");

        const char* s = PyBytes_AsString(PyUnicode_AsUTF8String(x)); 

        Py_DECREF(x);

        return pyBox_sayHi_char(self, s);
    }
    else
    {
        Py_RETURN_NOTIMPLEMENTED;
    }

    Py_RETURN_NOTIMPLEMENTED;
}

static PyMethodDef pyBox_methods[] = {
    {"Hi", (PyCFunction)Hi_overload_switch, METH_VARARGS, "Hi"},
    {NULL, NULL, 0, NULL}
};

However, when I go to python 3.7 and I run:

bo.Hi("John", 52364)

bo.Hi("Steve")

it prints the first statement but segfaults on Steve. Any suggestions why this is the case?

Thanks!

4
  • 1
    Python version? Commented May 21, 2019 at 16:50
  • ups! version 3.7 - thanks; edited the question Commented May 21, 2019 at 16:51
  • 1
    In your else if (PyLong_Check(x)) you're checking for long and then converting x to string... is it right? Commented May 21, 2019 at 16:57
  • well spotted! I have corrected in the question, however the result is the same! Commented May 21, 2019 at 17:12

2 Answers 2

2

Problem is here:

if (!PyArg_ParseTuple(args, "|OO", &x, &y))
    return NULL;

if (PyUnicode_Check(x) && PyLong_Check(y)) ...

You're taking two optional parameters (PyArg_ParseTuple does not modify the passed variables if no parameter is given). So bo.Hi("Steve") only populates x, but then you use y without checking it, thus the segfault. You must have been getting lucky with previous versions on the initial value of y.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! So how do I check for the number of arguments that were passed to Hi function?
In this case I'd set them to nullptr explicitly and then check that they're not null after calling PyArg_ParseTuple
Note that PyArg_ParseTuple does not increment the reference count for you in the event you need to retain the objects you have to do it yourself.
1

This fixes the issue (see answer by @gct to understand why):

static PyObject *Hi_overload_switch(PyBox *self,  PyObject *args)
{
PyObject *x = Py_None;
PyObject *y = Py_None;

if (!PyArg_ParseTuple(args, "|OO", &x, &y))
    {return NULL;}

if (PyUnicode_Check(x) && PyLong_Check(y) && y != Py_None)
{
    printf("A!\n\n");

    char* s = PyBytes_AsString(PyUnicode_AsUTF8String(x));

    Py_DECREF(x);

    return pyBox_sayHi_char_int(self, s, PyLong_AsLong(y));

}
else if (PyUnicode_Check(x) && y == Py_None)
{   
    printf("B!\n\n");

    char* s = PyBytes_AsString(PyUnicode_AsUTF8String(x)); 

    Py_DECREF(x);

    return pyBox_sayHi_char(self, s);
}
else
{
    Py_RETURN_NOTIMPLEMENTED;
}
Py_RETURN_NOTIMPLEMENTED;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.