Skip to content

Commit a0a9928

Browse files
committed
Fix refcounting bug in PLy_modify_tuple().
We must increment the refcount on "plntup" as soon as we have the reference, not sometime later. Otherwise, if an error is thrown in between, the Py_XDECREF(plntup) call in the PG_CATCH block removes a refcount we didn't add, allowing the object to be freed even though it's still part of the plpython function's parsetree. This appears to be the cause of crashes seen on buildfarm member prairiedog. It's a bit surprising that we've not seen it fail repeatably before, considering that the regression tests have been exercising the faulty code path since 2009. The real-world impact is probably minimal, since it's unlikely anyone would be provoking the "TD["new"] is not a dictionary" error in production, and that's the only case that is actually wrong. Still, it's a bug affecting the regression tests, so patch all supported branches. In passing, remove dead variable "plstr", and demote "platt" to a local variable inside the PG_TRY block, since we don't need to clean it up in the PG_CATCH path.
1 parent a8603f0 commit a0a9928

File tree

1 file changed

+3
-5
lines changed

1 file changed

+3
-5
lines changed

src/pl/plpython/plpython.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -769,9 +769,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
769769
{
770770
PyObject *volatile plntup;
771771
PyObject *volatile plkeys;
772-
PyObject *volatile platt;
773772
PyObject *volatile plval;
774-
PyObject *volatile plstr;
775773
HeapTuple rtup;
776774
int natts,
777775
i,
@@ -787,7 +785,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
787785
plerrcontext.previous = error_context_stack;
788786
error_context_stack = &plerrcontext;
789787

790-
plntup = plkeys = platt = plval = plstr = NULL;
788+
plntup = plkeys = plval = NULL;
791789
modattrs = NULL;
792790
modvalues = NULL;
793791
modnulls = NULL;
@@ -797,10 +795,10 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
797795
if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
798796
ereport(ERROR,
799797
(errmsg("TD[\"new\"] deleted, cannot modify row")));
798+
Py_INCREF(plntup);
800799
if (!PyDict_Check(plntup))
801800
ereport(ERROR,
802801
(errmsg("TD[\"new\"] is not a dictionary")));
803-
Py_INCREF(plntup);
804802

805803
plkeys = PyDict_Keys(plntup);
806804
natts = PyList_Size(plkeys);
@@ -813,6 +811,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
813811

814812
for (i = 0; i < natts; i++)
815813
{
814+
PyObject *platt;
816815
char *plattstr;
817816

818817
platt = PyList_GetItem(plkeys, i);
@@ -879,7 +878,6 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
879878
Py_XDECREF(plntup);
880879
Py_XDECREF(plkeys);
881880
Py_XDECREF(plval);
882-
Py_XDECREF(plstr);
883881

884882
if (modnulls)
885883
pfree(modnulls);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy