Skip to content

Commit 5b668ac

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 0af5fd8 commit 5b668ac

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
@@ -657,9 +657,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
657657
{
658658
PyObject *volatile plntup;
659659
PyObject *volatile plkeys;
660-
PyObject *volatile platt;
661660
PyObject *volatile plval;
662-
PyObject *volatile plstr;
663661
HeapTuple rtup;
664662
int natts,
665663
i,
@@ -675,7 +673,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
675673
plerrcontext.previous = error_context_stack;
676674
error_context_stack = &plerrcontext;
677675

678-
plntup = plkeys = platt = plval = plstr = NULL;
676+
plntup = plkeys = plval = NULL;
679677
modattrs = NULL;
680678
modvalues = NULL;
681679
modnulls = NULL;
@@ -685,10 +683,10 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
685683
if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
686684
ereport(ERROR,
687685
(errmsg("TD[\"new\"] deleted, cannot modify row")));
686+
Py_INCREF(plntup);
688687
if (!PyDict_Check(plntup))
689688
ereport(ERROR,
690689
(errmsg("TD[\"new\"] is not a dictionary")));
691-
Py_INCREF(plntup);
692690

693691
plkeys = PyDict_Keys(plntup);
694692
natts = PyList_Size(plkeys);
@@ -701,6 +699,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
701699

702700
for (i = 0; i < natts; i++)
703701
{
702+
PyObject *platt;
704703
char *plattstr;
705704

706705
platt = PyList_GetItem(plkeys, i);
@@ -767,7 +766,6 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
767766
Py_XDECREF(plntup);
768767
Py_XDECREF(plkeys);
769768
Py_XDECREF(plval);
770-
Py_XDECREF(plstr);
771769

772770
if (modnulls)
773771
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