Repository: numpy/numpy
File: numpy/_core/src/multiarray/arrayobject.c (C)

Code before:

/*
 * Much of the actual work for dealloc, split off for use in __setstate__
 * via dealloc_all_but_self function defined below.
 * If not unraisable, will return -1 on error, 0 on success.
 * If unraisable, always succeeds.
 */
static int
_dealloc_all_but_self(PyArrayObject *self, npy_bool unraisable)
{
    PyArrayObject_fields *fa = (PyArrayObject_fields *)self;
    int retval;

    if (fa->_buffer_info) {
        if (_buffer_info_free(fa->_buffer_info, (PyObject *)self) < 0) {
            if (!unraisable) {
                return -1;
            }
            PyErr_WriteUnraisable(NULL);
        }
        fa->_buffer_info = NULL;
    }

    if (fa->base) {
        if (PyArray_FLAGS(self) & NPY_ARRAY_WRITEBACKIFCOPY)
        {
            char const * msg = "WRITEBACKIFCOPY detected in array_dealloc. "
                " Required call to PyArray_ResolveWritebackIfCopy or "
                "PyArray_DiscardWritebackIfCopy is missing.";
            if (WARN_IN_DEALLOC(PyExc_RuntimeWarning, msg, unraisable) < 0) {
                return -1;  // Can only happen if !unraisable, so pass on.
            }
            retval = PyArray_ResolveWritebackIfCopy(self);
            if (retval < 0)
            {
                if (!unraisable) {
                    return -1;
                }
                PyErr_Print();
                PyErr_Clear();
            }
        }
        /*
         * If fa->base is non-NULL, it is something
         * to DECREF -- either a view or a buffer object
         */
        Py_CLEAR(fa->base);
    }
    else if ((fa->flags & NPY_ARRAY_OWNDATA) && fa->data) {
        /* Free any internal references */
        if (PyDataType_REFCHK(fa->descr)) {

Review comment (bug):
I don't understand at all why this was there -- if there is a piece of code that tries to defref self again, it is a bug, and should be exposed. Given that tests pass without it, it doesn't seem to be necessary (any more?).

Code after:
/*
 * Much of the actual work for dealloc, split off for use in __setstate__
 * via clear_array_attributes function defined below.
 * If not unraisable, will return -1 on error, 0 on success.
 * If unraisable, always succeeds, though may print errors and warnings.
 */
static int
_clear_array_attributes(PyArrayObject *self, npy_bool unraisable)
{
    PyArrayObject_fields *fa = (PyArrayObject_fields *)self;

    if (_buffer_info_free(fa->_buffer_info, (PyObject *)self) < 0) {
        if (write_and_clear_error_if_unraisable(-1, unraisable) < 0) {
            return -1;
        }
    }
    fa->_buffer_info = NULL;

    if (fa->base) {
        if (PyArray_FLAGS(self) & NPY_ARRAY_WRITEBACKIFCOPY)
        {
            char const * msg = "WRITEBACKIFCOPY detected in clearing of array. "
                " Required call to PyArray_ResolveWritebackIfCopy or "
                "PyArray_DiscardWritebackIfCopy is missing.";
            int retval = PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1);
            if (write_and_clear_error_if_unraisable(retval, unraisable) < 0) {
                return -1;
            }
            /*
             * prevent reaching 0 twice and thus recursing into dealloc.
             * Increasing sys.gettotalrefcount, but path should not be taken.
             */
            Py_INCREF(self);
            retval = PyArray_ResolveWritebackIfCopy(self);
            if (write_and_clear_error_if_unraisable(retval, unraisable) < 0) {
                return -1;
            }
        }
        /*
         * If fa->base is non-NULL, it is something
         * to DECREF -- either a view or a buffer object
         */
        Py_CLEAR(fa->base);
    }

    if ((fa->flags & NPY_ARRAY_OWNDATA) && fa->data) {
        /* Free any internal references */
        if (PyDataType_REFCHK(fa->descr)) {
            if (PyArray_ClearArray(self) < 0) {
                if (write_and_clear_error_if_unraisable(-1, unraisable) < 0) {
                    return -1;