diff --git a/src/backend/utils/cache/funccache.c b/src/backend/utils/cache/funccache.c
index 150c502a612..a5e9408cf55 100644
--- a/src/backend/utils/cache/funccache.c
+++ b/src/backend/utils/cache/funccache.c
@@ -491,6 +491,7 @@ cached_function_compile(FunctionCallInfo fcinfo,
 	CachedFunctionHashKey hashkey;
 	bool		function_valid = false;
 	bool		hashkey_valid = false;
+	bool		new_function = false;
 
 	/*
 	 * Lookup the pg_proc tuple by Oid; we'll need it in any case
@@ -570,13 +571,15 @@ recheck:
 
 		/*
 		 * Create the new function struct, if not done already.  The function
-		 * structs are never thrown away, so keep them in TopMemoryContext.
+		 * cache entry will be kept for the life of the backend, so put it in
+		 * TopMemoryContext.
 		 */
 		Assert(cacheEntrySize >= sizeof(CachedFunction));
 		if (function == NULL)
 		{
 			function = (CachedFunction *)
 				MemoryContextAllocZero(TopMemoryContext, cacheEntrySize);
+			new_function = true;
 		}
 		else
 		{
@@ -585,17 +588,35 @@ recheck:
 		}
 
 		/*
-		 * Fill in the CachedFunction part.  fn_hashkey and use_count remain
-		 * zeroes for now.
+		 * However, if function compilation fails, we'd like not to leak the
+		 * function struct, so use a PG_TRY block to prevent that.  (It's up
+		 * to the compile callback function to avoid its own internal leakage
+		 * in such cases.)  Unfortunately, freeing the struct is only safe if
+		 * we just allocated it: otherwise there are probably fn_extra
+		 * pointers to it.
 		 */
-		function->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
-		function->fn_tid = procTup->t_self;
-		function->dcallback = dcallback;
+		PG_TRY();
+		{
+			/*
+			 * Fill in the CachedFunction part.  fn_hashkey and use_count
+			 * remain zeroes for now.
+			 */
+			function->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
+			function->fn_tid = procTup->t_self;
+			function->dcallback = dcallback;
 
-		/*
-		 * Do the hard, language-specific part.
-		 */
-		ccallback(fcinfo, procTup, &hashkey, function, forValidator);
+			/*
+			 * Do the hard, language-specific part.
+			 */
+			ccallback(fcinfo, procTup, &hashkey, function, forValidator);
+		}
+		PG_CATCH();
+		{
+			if (new_function)
+				pfree(function);
+			PG_RE_THROW();
+		}
+		PG_END_TRY();
 
 		/*
 		 * Add the completed struct to the hash table.
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 5f3e8646fbb..22af973aae2 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -230,8 +230,13 @@ plpgsql_compile_callback(FunctionCallInfo fcinfo,
 	/*
 	 * All the permanent output of compilation (e.g. parse tree) is kept in a
 	 * per-function memory context, so it can be reclaimed easily.
+	 *
+	 * While the func_cxt needs to be long-lived, we initially make it a child
+	 * of the assumed-short-lived caller's context, and reparent it under
+	 * CacheMemoryContext only upon success.  This arrangement avoids memory
+	 * leakage during compilation of a faulty function.
 	 */
-	func_cxt = AllocSetContextCreate(TopMemoryContext,
+	func_cxt = AllocSetContextCreate(CurrentMemoryContext,
 									 "PL/pgSQL function",
 									 ALLOCSET_DEFAULT_SIZES);
 	plpgsql_compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
@@ -707,6 +712,11 @@ plpgsql_compile_callback(FunctionCallInfo fcinfo,
 	if (plpgsql_DumpExecTree)
 		plpgsql_dumptree(function);
 
+	/*
+	 * All is well, so make the func_cxt long-lived
+	 */
+	MemoryContextSetParent(func_cxt, CacheMemoryContext);
+
 	/*
 	 * Pop the error context stack
 	 */
