8000 Fix refcounting bug in PLy_modify_tuple(). · larkly/postgres-docker@8f9f73d · GitHub
[go: up one dir, main page]

Skip to content

Commit 8f9f73d

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 de13cea commit 8f9f73d

File tree

1 file changed

+3
-3
lines changed

1 file changed

+3
-3
lines changed

src/pl/plpython/plpython.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,6 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
476476
{
477477
PyObject *volatile plntup;
478478
PyObject *volatile plkeys;
479-
PyObject *volatile platt;
480479
PyObject *volatile plval;
481480
PyObject *volatile plstr;
482481
HeapTuple rtup;
@@ -489,7 +488,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
489488
char *volatile modnulls;
490489
TupleDesc tupdesc;
491490

492-
plntup = plkeys = platt = plval = plstr = NULL;
491+
plntup = plkeys = plval = plstr = NULL;
493492
modattrs = NULL;
494493
modvalues = NULL;
495494
modnulls = NULL;
@@ -499,10 +498,10 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
499498
if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
500499
ereport(ERROR,
501500
(errmsg("TD[\"new\"] deleted, cannot modify row")));
501+
Py_INCREF(plntup);
502502
if (!PyDict_Check(plntup))
503503
ereport(ERROR,
504504
(errmsg("TD[\"new\"] is not a dictionary")));
505-
Py_INCREF(plntup);
506505

507506
plkeys = PyDict_Keys(plntup);
508507
natts = PyList_Size(plkeys);
@@ -515,6 +514,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
515514

516515
for (i = 0; i < natts; i++)
517516
{
517+
PyObject *platt;
518518
char *src;
519519

520520
platt = PyList_GetItem(plkeys, i);

0 commit comments

Comments
 (0)
0