Re: PL/Python: Fix return in the middle of PG_TRY() block. - Mailing list pgsql-hackers

From Andres Freund
Subject Re: PL/Python: Fix return in the middle of PG_TRY() block.
Date
Msg-id 20230113054900.b7onkvwtkrykeu3z@awork3.anarazel.de
Whole thread Raw
In response to Re: PL/Python: Fix return in the middle of PG_TRY() block.  (Nathan Bossart <nathandbossart@gmail.com>)
Responses Re: PL/Python: Fix return in the middle of PG_TRY() block.
Re: PL/Python: Fix return in the middle of PG_TRY() block.
List pgsql-hackers
Hi,

On 2023-01-12 10:44:33 -0800, Nathan Bossart wrote:
> On Thu, Jan 12, 2023 at 11:19:29PM +0800, Xing Guo wrote:
> > @@ -690,12 +690,12 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
> >      PyObject   *volatile pltdata = NULL;
> >      char       *stroid;
> >  
> > +    pltdata = PyDict_New();
> > +    if (!pltdata)
> > +        return NULL;
> > +
> >      PG_TRY();
> >      {
> > -        pltdata = PyDict_New();
> > -        if (!pltdata)
> > -            return NULL;
> > -
> >          pltname = PLyUnicode_FromString(tdata->tg_trigger->tgname);
> >          PyDict_SetItemString(pltdata, "name", pltname);
> >          Py_DECREF(pltname);
> 
> There's another "return" later on in this PG_TRY block.  I wonder if it's
> possible to detect this sort of thing at compile time.

Clang provides some annotations that allow to detect this kind of thing. I
hacked up a test for this, and it finds quite a bit of prolematic
code. plpython is, uh, not being good? But also in plperl, pltcl.

Example complaints:

[776/1239 42  62%] Compiling C object src/pl/plpython/plpython3.so.p/plpy_exec.c.o
../../../../home/andres/src/postgresql/src/pl/plpython/plpy_exec.c:472:1: warning: no_returns_in_pg_try
'no_returns_handle'is not held on every path through here [-Wthread-safety-analysis]
 
}
^
../../../../home/andres/src/postgresql/src/pl/plpython/plpy_exec.c:417:2: note: no_returns_in_pg_try acquired here
        PG_TRY();
        ^
../../../../home/andres/src/postgresql/src/include/utils/elog.h:424:7: note: expanded from macro 'PG_TRY'
                    no_returns_start(no_returns_handle##__VA_ARGS__)
                    ^
...
[785/1239 42  63%] Compiling C object src/pl/tcl/pltcl.so.p/pltcl.c.o
../../../../home/andres/src/postgresql/src/pl/tcl/pltcl.c:1830:1: warning: no_returns_in_pg_try 'no_returns_handle' is
notheld on every path through here [-Wthread-safety-analysis]
 
}
^
../../../../home/andres/src/postgresql/src/pl/tcl/pltcl.c:1809:2: note: no_returns_in_pg_try acquired here
        PG_CATCH();
        ^
../../../../home/andres/src/postgresql/src/include/utils/elog.h:433:7: note: expanded from macro 'PG_CATCH'
                    no_returns_start(no_returns_handle##__VA_ARGS__)
                    ^

Not perfect digestible, but also not too bad. I pushed the
no_returns_start()/no_returns_stop() calls into all the PG_TRY related macros,
because that causes the warning to point to block that the problem is
in. E.g. above the first warning points to PG_TRY, the second to
PG_CATCH. It'd work to just put it into PG_TRY and PG_END_TRY.


Clearly this would need a bunch more work, but it seems promising? I think
there'd be other uses than this.


I briefly tried to use it for spinlocks. Mostly works and detects things like
returning with a spinlock held. But it does not like dynahash's habit of
conditionally acquiring and releasing spinlocks.

Greetings,

Andres Freund

Attachment

pgsql-hackers by date:

Previous
From: Masahiko Sawada
Date:
Subject: Re: Perform streaming logical transactions by background workers and parallel apply
Next
From: Andres Freund
Date:
Subject: Re: Cygwin cleanup