Thread

Commits

  1. Fix resource leaks in PL/Python error reporting, redux.

  2. Fix edge-case resource leaks in PL/Python error reporting.

  1. Memory leak due to thinko in PL/Python error handling

    Tom Lane <tgl@sss.pgh.pa.us> — 2025-10-23T01:49:19Z

    I have realized that there's an oversight in my recent commit
    c6f7f11d8, which so far from preventing edge-case leaks as intended,
    actually introduces a memory leak in the normal error-catching path.
    The leakage is easy to see if you extract the
    catch_python_unique_violation() test case from plpython_error.sql
    and run it in a loop, like
    
    pl_regression=# do $$                                  
    begin
    for i in 1..1000000 loop
    perform catch_python_unique_violation();
    end loop; end$$;
    
    The backend's VIRT size as reported by top(1) will grow steadily.
    
    The problem is that I did not think through the fact that
    PyObject_GetAttrString() acquires a refcount on the returned object,
    so that after advancing to the next frame object with
    
             tb = PyObject_GetAttrString(tb, "tb_next");
    
    we have an extra refcount on the new "tb" object, and there's no logic
    that will get rid of that.  The loop that I introduced with an eye to
    cleaning things up:
    
            /* Must release all the objects in the traceback stack */
            while (tb != NULL && tb != Py_None)
            {
                PyObject   *tb_prev = tb;
    
                tb = PyObject_GetAttrString(tb, "tb_next");
                Py_DECREF(tb_prev);
            }
    
    isn't right either, since it likewise doesn't account for the
    extra refcount added by PyObject_GetAttrString.
    
    The correct fix, I believe, is as attached.  If we avoid collecting
    extra refcounts during PLy_traceback(), then PLy_elog_impl() can go
    back to simply doing Py_XDECREF(tb) on the first frame.  Any
    additional frames will go away when the previous frame object is
    cleaned up and drops its refcount.
    
    I also added a couple of comments explaining why PLy_elog_impl()
    doesn't try to free the strings acquired from PLy_get_spi_error_data()
    or PLy_get_error_data().  That's because I got here by looking at a
    Coverity complaint about how those strings might get leaked.  They
    are not leaked, but in testing that I discovered this other leak.
    
    			regards, tom lane