Fix ExecuteCallStmt to not scribble on the passed-in parse tree.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 4 Nov 2018 19:50:55 +0000 (14:50 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 4 Nov 2018 19:50:55 +0000 (14:50 -0500)
Modifying the parse tree at execution time is, or at least ought to be,
verboten.  It seems quite difficult to actually cause a crash this way
in v11 (although you can exhibit it pretty easily in HEAD by messing
with plan_cache_mode).  Nonetheless, it's risky, so fix and back-patch.

Discussion: https://postgr.es/m/13789.1541359611@sss.pgh.pa.us

src/backend/commands/functioncmds.c

index 3fd73a69f04ff16afd00e07efde9c533c49e0aea..3925fb83a5438e09fb1f5dee5c9f77f71170ed54 100644 (file)
@@ -2225,6 +2225,7 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
 
    fexpr = stmt->funcexpr;
    Assert(fexpr);
+   Assert(IsA(fexpr, FuncExpr));
 
    aclresult = pg_proc_aclcheck(fexpr->funcid, GetUserId(), ACL_EXECUTE);
    if (aclresult != ACLCHECK_OK)
@@ -2253,13 +2254,25 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
     * and AbortTransaction() resets the security context.  This could be
     * reorganized, but right now it doesn't work.
     */
-   if (((Form_pg_proc )GETSTRUCT(tp))->prosecdef)
+   if (((Form_pg_procGETSTRUCT(tp))->prosecdef)
        callcontext->atomic = true;
 
    /*
-    * Expand named arguments, defaults, etc.
+    * Expand named arguments, defaults, etc.  We do not want to scribble on
+    * the passed-in CallStmt parse tree, so first flat-copy fexpr, allowing
+    * us to replace its args field.  (Note that expand_function_arguments
+    * will not modify any of the passed-in data structure.)
     */
-   fexpr->args = expand_function_arguments(fexpr->args, fexpr->funcresulttype, tp);
+   {
+       FuncExpr   *nexpr = makeNode(FuncExpr);
+
+       memcpy(nexpr, fexpr, sizeof(FuncExpr));
+       fexpr = nexpr;
+   }
+
+   fexpr->args = expand_function_arguments(fexpr->args,
+                                           fexpr->funcresulttype,
+                                           tp);
    nargs = list_length(fexpr->args);
 
    ReleaseSysCache(tp);
@@ -2362,8 +2375,8 @@ TupleDesc
 CallStmtResultDesc(CallStmt *stmt)
 {
    FuncExpr   *fexpr;
-   HeapTuple   tuple;
-   TupleDesc   tupdesc;
+   HeapTuple   tuple;
+   TupleDesc   tupdesc;
 
    fexpr = stmt->funcexpr;