Thread

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Move return statements out of PG_TRY blocks.

  1. PL/Python: Fix return in the middle of PG_TRY() block.

    Xing Guo <higuoxing@gmail.com> — 2023-01-12T15:19:29Z

    Hi hackers,
    
    I was running static analyser against PostgreSQL and found there're 2
    return statements in PL/Python module which is not safe. Patch is
    attached.
    
    -- 
    Best Regards,
    Xing
    
  2. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Nathan Bossart <nathandbossart@gmail.com> — 2023-01-12T18:44:33Z

    On Thu, Jan 12, 2023 at 11:19:29PM +0800, Xing Guo wrote:
    > I was running static analyser against PostgreSQL and found there're 2
    > return statements in PL/Python module which is not safe. Patch is
    > attached.
    
    Is the problem that PG_exception_stack and error_context_stack aren't
    properly reset?
    
    > @@ -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.
    
    -- 
    Nathan Bossart
    Amazon Web Services: https://aws.amazon.com
    
    
    
    
  3. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Michael Paquier <michael@paquier.xyz> — 2023-01-13T01:45:59Z

    On Thu, Jan 12, 2023 at 10:44:33AM -0800, Nathan Bossart wrote:
    > 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.
    
    Note also:
    src/pl/tcl/pltcl.c- *   PG_CATCH();
    src/pl/tcl/pltcl.c- *   {
    src/pl/tcl/pltcl.c- *       pltcl_subtrans_abort(interp, oldcontext, oldowner);
    src/pl/tcl/pltcl.c- *       return TCL_ERROR;
    src/pl/tcl/pltcl.c- *   }
    
    This is documented once, repeated twice:
    src/pl/plpython/plpy_spi.c- *   PG_CATCH();
    src/pl/plpython/plpy_spi.c- *   {
    src/pl/plpython/plpy_spi.c- *       <do cleanup>
    src/pl/plpython/plpy_spi.c- *       PLy_spi_subtransaction_abort(oldcontext, oldowner);
    src/pl/plpython/plpy_spi.c- *       return NULL;
    src/pl/plpython/plpy_spi.c- *   }
    
    I don't quite get why this would be a sane thing to do here when
    aborting a subtransaction in pl/python, but my experience with this
    code is limited.
    --
    Michael
    
  4. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Andres Freund <andres@anarazel.de> — 2023-01-13T05:49:00Z

    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 not held 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
    
  5. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Andres Freund <andres@anarazel.de> — 2023-01-13T07:23:46Z

    Hi,
    
    On 2023-01-12 21:49:00 -0800, Andres Freund wrote:
    > 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.
    
    One example is to prevent things like elog()/ereport()/SpinlockAcquire() while
    holding a spinlock
    
    The "locks_excluded(thing)" attribute (which is just heuristic, doesn't require
    expansive annotation like requires_capability(!thing)), can quite easily be
    used to trigger warnings about this kind of thing:
    
    ../../../../home/andres/src/postgresql/src/backend/access/transam/xlog.c:6771:2: warning: cannot call function 'errstart' while no_nested_spinlock 'in_spinlock' is held [-Wthread-safety-analysis]
            elog(LOG, "logging with spinlock held");
    
    
    Greetings,
    
    Andres Freund
    
    
    
    
  6. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Xing Guo <higuoxing@gmail.com> — 2023-01-13T15:00:14Z

    Hi Nathan.
    
    On 1/13/23, Nathan Bossart <nathandbossart@gmail.com> wrote:
    > On Thu, Jan 12, 2023 at 11:19:29PM +0800, Xing Guo wrote:
    >> I was running static analyser against PostgreSQL and found there're 2
    >> return statements in PL/Python module which is not safe. Patch is
    >> attached.
    >
    > Is the problem that PG_exception_stack and error_context_stack aren't
    > properly reset?
    
    Yes, it is.
    
    >
    >> @@ -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.
    
    Thanks for pointing it out! I missed some return statements. Because
    my checker is treating 'return statement in PG_TRY() block' as errors.
    It stops compiling when it finds the code pattern and I forget to
    double check it.
    
    My checker is based on AST matcher and it's possible to turn it into a
    clang-tidy plugin or something similar. I want to make it easy to
    integrate with scan-build, so I implement it as a static analyzer
    plugin :)
    
    If anyone is interested in the checker itself, the source code can be
    found here[1]:
    
    > Note also:
    > src/pl/tcl/pltcl.c- *   PG_CATCH();
    > src/pl/tcl/pltcl.c- *   {
    > src/pl/tcl/pltcl.c- *       pltcl_subtrans_abort(interp, oldcontext,
    > oldowner);
    > src/pl/tcl/pltcl.c- *       return TCL_ERROR;
    > src/pl/tcl/pltcl.c- *   }
    >
    > This is documented once, repeated twice:
    > src/pl/plpython/plpy_spi.c- *   PG_CATCH();
    > src/pl/plpython/plpy_spi.c- *   {
    > src/pl/plpython/plpy_spi.c- *       <do cleanup>
    > src/pl/plpython/plpy_spi.c- *       PLy_spi_subtransaction_abort(oldcontext,
    > oldowner);
    > src/pl/plpython/plpy_spi.c- *       return NULL;
    > src/pl/plpython/plpy_spi.c- *   }
    >
    > I don't quite get why this would be a sane thing to do here when
    > aborting a subtransaction in pl/python, but my experience with this
    > code is limited.
    
    Hi Michael,
    
    I'll try to understand what's going on in your pasted codes. Thanks
    for pointing it out!
    
    > 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 not held 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__)
    >                     ^
    
    Hi Andres,
    
    Your patch looks interesting and useful. I will play with it in the
    next following days. I'm burried with other works recently, so my
    reply may delay.
    
    > 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
    >
    
    [1] https://github.com/higuoxing/clang-plugins/blob/main/lib/ReturnInPgTryBlockChecker.cpp
    
    -- 
    Best Regards,
    Xing
    
    
    
    
    
    
    
    
    
    On 1/13/23, Andres Freund <andres@anarazel.de> wrote:
    > Hi,
    >
    > On 2023-01-12 21:49:00 -0800, Andres Freund wrote:
    >> 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.
    >
    > One example is to prevent things like elog()/ereport()/SpinlockAcquire()
    > while
    > holding a spinlock
    >
    > The "locks_excluded(thing)" attribute (which is just heuristic, doesn't
    > require
    > expansive annotation like requires_capability(!thing)), can quite easily be
    > used to trigger warnings about this kind of thing:
    >
    > ../../../../home/andres/src/postgresql/src/backend/access/transam/xlog.c:6771:2:
    > warning: cannot call function 'errstart' while no_nested_spinlock
    > 'in_spinlock' is held [-Wthread-safety-analysis]
    >         elog(LOG, "logging with spinlock held");
    >
    >
    > Greetings,
    >
    > Andres Freund
    >
    
    
    -- 
    Best Regards,
    Xing
    
    
    
    
  7. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Nathan Bossart <nathandbossart@gmail.com> — 2023-01-13T18:03:35Z

    On Thu, Jan 12, 2023 at 09:49:00PM -0800, Andres Freund wrote:
    > On 2023-01-12 10:44:33 -0800, Nathan Bossart wrote:
    >> 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.
    
    Nice!
    
    > plpython is, uh, not being good? But also in plperl, pltcl.
    
    Yikes.
    
    > ../../../../home/andres/src/postgresql/src/pl/tcl/pltcl.c:1830: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/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.
    
    This seems roughly as digestible as the pg_prevent_errno_in_scope stuff.
    However, on my macOS machine with clang 14.0.0, the messages say "mutex"
    instead of "no_returns_in_pg_try," which is unfortunate since that's the
    part that would clue me into what the problem is.  I suppose it'd be easy
    enough to figure out after a grep or two, though.
    
    > Clearly this would need a bunch more work, but it seems promising? I think
    > there'd be other uses than this.
    
    +1
    
    -- 
    Nathan Bossart
    Amazon Web Services: https://aws.amazon.com
    
    
    
    
  8. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Xing Guo <higuoxing@gmail.com> — 2023-01-16T13:03:43Z

    Hi,
    
    I revised my patch, added the missing one that Nathan mentioned.
    
    Are there any unsafe codes in pltcl.c? The return statement is in the
    PG_CATCH() block, I think the exception stack has been recovered in
    PG_CATCH block so the return statement in PG_CATCH block should be ok?
    
    ```
    PG_TRY();
    {
    UTF_BEGIN;
    ereport(level,
    (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
    errmsg("%s", UTF_U2E(Tcl_GetString(objv[2])))));
    UTF_END;
    }
    PG_CATCH();
    {
    ErrorData  *edata;
    
    /* Must reset elog.c's state */
    MemoryContextSwitchTo(oldcontext);
    edata = CopyErrorData();
    FlushErrorState();
    
    /* Pass the error data to Tcl */
    pltcl_construct_errorCode(interp, edata);
    UTF_BEGIN;
    Tcl_SetObjResult(interp, Tcl_NewStringObj(UTF_E2U(edata->message), -1));
    UTF_END;
    FreeErrorData(edata);
    
    return TCL_ERROR;
    }
    PG_END_TRY();
    ```
    
    Best Regards,
    Xing
    
    
    
    
    
    
    
    
    On Sat, Jan 14, 2023 at 2:03 AM Nathan Bossart <nathandbossart@gmail.com>
    wrote:
    
    > On Thu, Jan 12, 2023 at 09:49:00PM -0800, Andres Freund wrote:
    > > On 2023-01-12 10:44:33 -0800, Nathan Bossart wrote:
    > >> 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.
    >
    > Nice!
    >
    > > plpython is, uh, not being good? But also in plperl, pltcl.
    >
    > Yikes.
    >
    > > ../../../../home/andres/src/postgresql/src/pl/tcl/pltcl.c:1830: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/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.
    >
    > This seems roughly as digestible as the pg_prevent_errno_in_scope stuff.
    > However, on my macOS machine with clang 14.0.0, the messages say "mutex"
    > instead of "no_returns_in_pg_try," which is unfortunate since that's the
    > part that would clue me into what the problem is.  I suppose it'd be easy
    > enough to figure out after a grep or two, though.
    >
    > > Clearly this would need a bunch more work, but it seems promising? I
    > think
    > > there'd be other uses than this.
    >
    > +1
    >
    > --
    > Nathan Bossart
    > Amazon Web Services: https://aws.amazon.com
    >
    
  9. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Tom Lane <tgl@sss.pgh.pa.us> — 2023-01-16T15:29:03Z

    Xing Guo <higuoxing@gmail.com> writes:
    > Are there any unsafe codes in pltcl.c? The return statement is in the
    > PG_CATCH() block, I think the exception stack has been recovered in
    > PG_CATCH block so the return statement in PG_CATCH block should be ok?
    
    Yes, the stack has already been unwound at the start of a PG_CATCH
    (or PG_FINALLY) block, so there is no reason to avoid returning
    out of those.
    
    In principle you could also mess things up with a "continue", "break",
    or "goto" leading out of PG_TRY.  That's probably far less likely
    than "return", but I wonder whether Andres' compiler hack will
    catch that.
    
    			regards, tom lane
    
    
    
    
  10. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Xing Guo <higuoxing@gmail.com> — 2023-01-18T12:31:04Z

    On Mon, Jan 16, 2023 at 11:29 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
    
    > Xing Guo <higuoxing@gmail.com> writes:
    > > Are there any unsafe codes in pltcl.c? The return statement is in the
    > > PG_CATCH() block, I think the exception stack has been recovered in
    > > PG_CATCH block so the return statement in PG_CATCH block should be ok?
    >
    > Yes, the stack has already been unwound at the start of a PG_CATCH
    > (or PG_FINALLY) block, so there is no reason to avoid returning
    > out of those.
    >
    > In principle you could also mess things up with a "continue", "break",
    > or "goto" leading out of PG_TRY.  That's probably far less likely
    > than "return", but I wonder whether Andres' compiler hack will
    > catch that.
    >
    >                         regards, tom lane
    >
    
    Thank you Tom,
    
    Based on your comments, I've refactored my clang checker[1], now it can
    warn about the following patterns:
    1. return statement in PG_TRY(). We've catched all of them in this thread.
    2. continue statement in PG_TRY() *unless* it's in for/while/do-while
    statements.
    3. break statement in PG_TRY() *unless* it's in for/while/do-while/switch
    statements.
    4. goto statement in PG_TRY() *unless* the label it points to is in the
    same PG_TRY block.
    
    Good news is that, there's no patterns (2, 3, 4) in Postgres source tree
    and we've catched all of the return statements in the PG_TRY block in this
    thread.
    
    [1]
    https://github.com/higuoxing/clang-plugins/blob/main/lib/ReturnInPgTryBlockChecker.cpp
    
    Best Regards,
    Xing
    
  11. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Andres Freund <andres@anarazel.de> — 2023-01-20T01:07:11Z

    Hi,
    
    On 2023-01-16 10:29:03 -0500, Tom Lane wrote:
    > Xing Guo <higuoxing@gmail.com> writes:
    > > Are there any unsafe codes in pltcl.c? The return statement is in the
    > > PG_CATCH() block, I think the exception stack has been recovered in
    > > PG_CATCH block so the return statement in PG_CATCH block should be ok?
    > 
    > Yes, the stack has already been unwound at the start of a PG_CATCH
    > (or PG_FINALLY) block, so there is no reason to avoid returning
    > out of those.
    
    It's probably true for PG_CATCH, but for PG_FINALLY? Won't returning lead us
    to miss rethrowing the error? I guess you can argue that's desired, but then
    why would one use PG_FINALLY?
    
    
    I'm somewhat dubious about allowing to return inside PG_CATCH, even if it's
    safe today.
    
    
    > In principle you could also mess things up with a "continue", "break",
    > or "goto" leading out of PG_TRY.  That's probably far less likely
    > than "return", but I wonder whether Andres' compiler hack will
    > catch that.
    
    I haven't tested it, but it should - it basically traces every path and sees
    whether there's any way the "capability" isn't released. To the point that
    it's very annoying in other contexts, because it doesn't deal well with
    conditional lock acquisition/releases.
    
    Greetings,
    
    Andres Freund
    
    
    
    
  12. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Nathan Bossart <nathandbossart@gmail.com> — 2023-01-20T19:02:01Z

    On Thu, Jan 19, 2023 at 05:07:11PM -0800, Andres Freund wrote:
    > I'm somewhat dubious about allowing to return inside PG_CATCH, even if it's
    > safe today.
    
    +1.  Unless there are known use-cases, IMHO it'd be better to restrict it
    to prevent future compatibility breaks as PG_TRY evolves.
    
    -- 
    Nathan Bossart
    Amazon Web Services: https://aws.amazon.com
    
    
    
    
  13. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Nathan Bossart <nathandbossart@gmail.com> — 2023-05-03T20:21:16Z

    Here's a new version of the patch.  Besides adding comments and a commit
    message, I made sure to decrement the reference count for pltargs in the
    PG_CATCH block (which means that pltargs likely needs to be volatile).  I'm
    not too wild about moving the chunk of code for pltargs like this, but I
    haven't thought of a better option.  We could error instead of returning
    NULL, but IIUC that would go against d0aa965's stated purpose.
    
    -- 
    Nathan Bossart
    Amazon Web Services: https://aws.amazon.com
    
  14. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Tom Lane <tgl@sss.pgh.pa.us> — 2023-05-03T20:33:32Z

    Nathan Bossart <nathandbossart@gmail.com> writes:
    > Here's a new version of the patch.  Besides adding comments and a commit
    > message, I made sure to decrement the reference count for pltargs in the
    > PG_CATCH block (which means that pltargs likely needs to be volatile).
    
    Hmm, actually I think these changes should allow you to *remove* some
    volatile markers.  IIUC, you need volatile for variables that are declared
    outside PG_TRY but modified within it.  That is the case for these
    pointers as the code stands, but your patch is changing them to the
    non-risky case where they are assigned once before entering PG_TRY.
    
    (My mental model of this is that without "volatile", the compiler
    may keep the variable in a register, creating the hazard that longjmp
    will revert the variable's value to what it was at setjmp time thanks
    to the register save/restore that those functions do.  But if it hasn't
    changed value since entering PG_TRY, then that doesn't matter.)
    
    > I'm
    > not too wild about moving the chunk of code for pltargs like this, but I
    > haven't thought of a better option.  We could error instead of returning
    > NULL, but IIUC that would go against d0aa965's stated purpose.
    
    Agreed, throwing an error in these situations doesn't improve matters.
    
    			regards, tom lane
    
    
    
    
  15. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Nathan Bossart <nathandbossart@gmail.com> — 2023-05-03T20:58:38Z

    On Wed, May 03, 2023 at 04:33:32PM -0400, Tom Lane wrote:
    > Nathan Bossart <nathandbossart@gmail.com> writes:
    >> Here's a new version of the patch.  Besides adding comments and a commit
    >> message, I made sure to decrement the reference count for pltargs in the
    >> PG_CATCH block (which means that pltargs likely needs to be volatile).
    > 
    > Hmm, actually I think these changes should allow you to *remove* some
    > volatile markers.  IIUC, you need volatile for variables that are declared
    > outside PG_TRY but modified within it.  That is the case for these
    > pointers as the code stands, but your patch is changing them to the
    > non-risky case where they are assigned once before entering PG_TRY.
    > 
    > (My mental model of this is that without "volatile", the compiler
    > may keep the variable in a register, creating the hazard that longjmp
    > will revert the variable's value to what it was at setjmp time thanks
    > to the register save/restore that those functions do.  But if it hasn't
    > changed value since entering PG_TRY, then that doesn't matter.)
    
    Ah, I think you are right.  elog.h states as follows:
    
     * Note: if a local variable of the function containing PG_TRY is modified
     * in the PG_TRY section and used in the PG_CATCH section, that variable
     * must be declared "volatile" for POSIX compliance.  This is not mere
     * pedantry; we have seen bugs from compilers improperly optimizing code
     * away when such a variable was not marked.  Beware that gcc's -Wclobbered
     * warnings are just about entirely useless for catching such oversights.
    
    With this change, pltdata isn't modified in the PG_TRY section, and the
    only modification of pltargs happens after all elogs.  It might be worth
    keeping pltargs volatile in case someone decides to add an elog() in the
    future, but I see no need to keep it for pltdata.
     
    -- 
    Nathan Bossart
    Amazon Web Services: https://aws.amazon.com
    
    
    
    
  16. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Nathan Bossart <nathandbossart@gmail.com> — 2023-05-04T04:54:13Z

    On Wed, May 03, 2023 at 01:58:38PM -0700, Nathan Bossart wrote:
    > With this change, pltdata isn't modified in the PG_TRY section, and the
    > only modification of pltargs happens after all elogs.  It might be worth
    > keeping pltargs volatile in case someone decides to add an elog() in the
    > future, but I see no need to keep it for pltdata.
    
    Here's a new patch that removes the volatile marker from pltdata.
    
    -- 
    Nathan Bossart
    Amazon Web Services: https://aws.amazon.com
    
  17. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Nathan Bossart <nathandbossart@gmail.com> — 2023-05-04T05:01:08Z

    On Wed, May 03, 2023 at 09:54:13PM -0700, Nathan Bossart wrote:
    > Here's a new patch that removes the volatile marker from pltdata.
    
    Gah, right after I sent that, I realized we can remove one more volatile
    marker.  Sorry for the noise.
    
    -- 
    Nathan Bossart
    Amazon Web Services: https://aws.amazon.com
    
  18. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Tom Lane <tgl@sss.pgh.pa.us> — 2023-05-04T12:39:03Z

    Nathan Bossart <nathandbossart@gmail.com> writes:
    > Gah, right after I sent that, I realized we can remove one more volatile
    > marker.  Sorry for the noise.
    
    Hmm, I'm not sure why PLy_trigger_build_args's pltargs needs to
    gain a "volatile" here?  LGTM otherwise.
    
    			regards, tom lane
    
    
    
    
  19. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Nathan Bossart <nathandbossart@gmail.com> — 2023-05-04T23:42:35Z

    On Thu, May 04, 2023 at 08:39:03AM -0400, Tom Lane wrote:
    > Hmm, I'm not sure why PLy_trigger_build_args's pltargs needs to
    > gain a "volatile" here?  LGTM otherwise.
    
    I removed that new "volatile" marker before committing.  I was trying to
    future-proof a bit and follow elog.h's recommendation to the letter, but
    following your mental model upthread, it doesn't seem to be strictly
    necessary, and we'd need to set pltargs to NULL after decrementing its
    reference count in the PG_TRY section for such future-proofing to be
    effective, anyway.
    
    Thank you for reviewing!
    
    -- 
    Nathan Bossart
    Amazon Web Services: https://aws.amazon.com
    
    
    
    
  20. Re: PL/Python: Fix return in the middle of PG_TRY() block.

    Xing Guo <higuoxing@gmail.com> — 2023-05-05T01:40:32Z

    Sorry for not responding to this thread for a long time and a huge thank
    you for pushing it forward!
    
    Best Regards,
    Xing
    
    
    
    
    
    
    
    
    On Fri, May 5, 2023 at 7:42 AM Nathan Bossart <nathandbossart@gmail.com>
    wrote:
    
    > On Thu, May 04, 2023 at 08:39:03AM -0400, Tom Lane wrote:
    > > Hmm, I'm not sure why PLy_trigger_build_args's pltargs needs to
    > > gain a "volatile" here?  LGTM otherwise.
    >
    > I removed that new "volatile" marker before committing.  I was trying to
    > future-proof a bit and follow elog.h's recommendation to the letter, but
    > following your mental model upthread, it doesn't seem to be strictly
    > necessary, and we'd need to set pltargs to NULL after decrementing its
    > reference count in the PG_TRY section for such future-proofing to be
    > effective, anyway.
    >
    > Thank you for reviewing!
    >
    > --
    > Nathan Bossart
    > Amazon Web Services: https://aws.amazon.com
    >