Implementing nb_inplace_add results in returning a read-only buffer object
Asked Answered
D

1

1

I'm writing an implementation of the in-place add operation. But, for some reason, I sometimes get a read-only buffer as result(while I'm adding a custom extension class and an integer...).

The relevant code is:

static PyObject *
ModPoly_InPlaceAdd(PyObject *self, PyObject *other)
{

    if (!ModPoly_Check(self)) {
        //Since it's in-place addition the control flow should never
        // enter here(I suppose)
        if (!ModPoly_Check(other)) {
            PyErr_SetString(PyExc_TypeError, "Neither argument is a ModPolynomial.");
            return NULL;
        }
        return ModPoly_InPlaceAdd(other, self);
    } else {
        if (!PyInt_Check(other) && !PyLong_Check(other)) {
            Py_INCREF(Py_NotImplemented);
            return Py_NotImplemented;
        }
    }

    ModPoly *Tself = (ModPoly *)self;
    PyObject *tmp, *tmp2;
    tmp = PyNumber_Add(Tself->ob_item[0], other);
    tmp2 = PyNumber_Remainder(tmp, Tself->n_modulus);

    Py_DECREF(tmp);
    tmp = Tself->ob_item[0];
    Tself->ob_item[0] = tmp2;
    Py_DECREF(tmp);
    return (PyObject *)Tself;

}

If instead of returning (PyObject*)Tself(or simply "self"), I raise an exception, the original object gets update correctly[checked using some printf]. If I use the Py_RETURN_NONE macro, it correctly turns the ModPoly into None (in the python side).

What am I doing wrong? I'm returning a pointer to a ModPoly object, how can this become a buffer? And I don't see any operation on those pointers.

example usage:

>>> from algebra import polynomials
>>> pol = polynomials.ModPolynomial(3,17)
>>> pol += 5
>>> pol
<read-only buffer ptr 0xf31420, size 4 at 0xe6faf0>

I've tried change the return line into:

printf("%d\n", (int)ModPoly_Check(self));
return self;

and it prints 1 when adding in-place (meaning that the value returned is of type ModPolynomial...)

Degrade answered 10/8, 2012 at 7:58 Comment(0)
I
2

According to the documentation, the inplace add operation for an object returns a new reference.

By returning self directly without calling Py_INCREF on it, your object will be freed while it is still referenced. If some other object is allocated the same piece of memory, those references would now give you the new object.

Insomniac answered 10/8, 2012 at 8:39 Comment(1)
You're right. This is my first C-extension, so I'm still trying to understand when I should INCREF/DECREF things.Degrade

© 2022 - 2024 — McMap. All rights reserved.