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 <nathandboss...@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
>
diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c
index 923703535a..7181b5e898 100644
--- a/src/pl/plpython/plpy_exec.c
+++ b/src/pl/plpython/plpy_exec.c
@@ -414,12 +414,12 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
 	PyObject   *volatile args = NULL;
 	int			i;
 
+	args = PyList_New(proc->nargs);
+	if (!args)
+		return NULL;
+
 	PG_TRY();
 	{
-		args = PyList_New(proc->nargs);
-		if (!args)
-			return NULL;
-
 		for (i = 0; i < proc->nargs; i++)
 		{
 			PLyDatumToOb *arginfo = &proc->args[i];
@@ -684,18 +684,28 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 			   *pltrelid,
 			   *plttablename,
 			   *plttableschema;
-	PyObject   *pltargs,
+	PyObject   *pltargs = NULL,
 			   *pytnew,
 			   *pytold;
 	PyObject   *volatile pltdata = NULL;
 	char	   *stroid;
 
-	PG_TRY();
+	pltdata = PyDict_New();
+	if (!pltdata)
+		return NULL;
+
+	if (tdata->tg_trigger->tgnargs)
 	{
-		pltdata = PyDict_New();
-		if (!pltdata)
+		pltargs = PyList_New(tdata->tg_trigger->tgnargs);
+		if (!pltargs)
+		{
+			Py_DECREF(pltdata);
 			return NULL;
+		}
+	}
 
+	PG_TRY();
+	{
 		pltname = PLyUnicode_FromString(tdata->tg_trigger->tgname);
 		PyDict_SetItemString(pltdata, "name", pltname);
 		Py_DECREF(pltname);
@@ -835,12 +845,6 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
 			int			i;
 			PyObject   *pltarg;
 
-			pltargs = PyList_New(tdata->tg_trigger->tgnargs);
-			if (!pltargs)
-			{
-				Py_DECREF(pltdata);
-				return NULL;
-			}
 			for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
 			{
 				pltarg = PLyUnicode_FromString(tdata->tg_trigger->tgargs[i]);

Reply via email to