diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 50c3c3b..1eabc67 100644
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
*************** AbortOutOfAnyTransaction(void)
*** 4233,4238 ****
--- 4233,4241 ----
  {
  	TransactionState s = CurrentTransactionState;
  
+ 	/* Ensure we're not running in a doomed memory context */
+ 	AtAbort_Memory();
+ 
  	/*
  	 * Get out of any transaction or nested transaction
  	 */
*************** AbortOutOfAnyTransaction(void)
*** 4274,4280 ****
  				break;
  			case TBLOCK_ABORT:
  			case TBLOCK_ABORT_END:
! 				/* AbortTransaction already done, still need Cleanup */
  				CleanupTransaction();
  				s->blockState = TBLOCK_DEFAULT;
  				break;
--- 4277,4290 ----
  				break;
  			case TBLOCK_ABORT:
  			case TBLOCK_ABORT_END:
! 
! 				/*
! 				 * AbortTransaction is already done, still need Cleanup.
! 				 * However, if we failed partway through running ROLLBACK,
! 				 * there will be an active portal running that command, which
! 				 * we need to shut down before doing CleanupTransaction.
! 				 */
! 				AtAbort_Portals();
  				CleanupTransaction();
  				s->blockState = TBLOCK_DEFAULT;
  				break;
*************** AbortOutOfAnyTransaction(void)
*** 4297,4302 ****
--- 4307,4320 ----
  			case TBLOCK_SUBABORT_END:
  			case TBLOCK_SUBABORT_RESTART:
  				/* As above, but AbortSubTransaction already done */
+ 				if (s->curTransactionOwner)
+ 				{
+ 					/* As in TBLOCK_ABORT, might have a live portal to zap */
+ 					AtSubAbort_Portals(s->subTransactionId,
+ 									   s->parent->subTransactionId,
+ 									   s->curTransactionOwner,
+ 									   s->parent->curTransactionOwner);
+ 				}
  				CleanupSubTransaction();
  				s = CurrentTransactionState;	/* changed by pop */
  				break;
*************** AbortOutOfAnyTransaction(void)
*** 4305,4310 ****
--- 4323,4331 ----
  
  	/* Should be out of all subxacts now */
  	Assert(s->parent == NULL);
+ 
+ 	/* If we didn't actually have anything to do, revert to TopMemoryContext */
+ 	AtCleanup_Memory();
  }
  
  /*
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 5983aed..e3a3526 100644
*** a/src/backend/utils/mmgr/portalmem.c
--- b/src/backend/utils/mmgr/portalmem.c
*************** AtCleanup_Portals(void)
*** 842,849 ****
  		if (portal->portalPinned)
  			portal->portalPinned = false;
  
! 		/* We had better not be calling any user-defined code here */
! 		Assert(portal->cleanup == NULL);
  
  		/* Zap it. */
  		PortalDrop(portal, false);
--- 842,856 ----
  		if (portal->portalPinned)
  			portal->portalPinned = false;
  
! 		/*
! 		 * We had better not call any user-defined code during cleanup, so if
! 		 * the cleanup hook hasn't been run yet, too bad.
! 		 */
! 		if (PointerIsValid(portal->cleanup))
! 		{
! 			elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
! 			portal->cleanup = NULL;
! 		}
  
  		/* Zap it. */
  		PortalDrop(portal, false);
*************** AtSubCleanup_Portals(SubTransactionId my
*** 1026,1033 ****
  		if (portal->portalPinned)
  			portal->portalPinned = false;
  
! 		/* We had better not be calling any user-defined code here */
! 		Assert(portal->cleanup == NULL);
  
  		/* Zap it. */
  		PortalDrop(portal, false);
--- 1033,1047 ----
  		if (portal->portalPinned)
  			portal->portalPinned = false;
  
! 		/*
! 		 * We had better not call any user-defined code during cleanup, so if
! 		 * the cleanup hook hasn't been run yet, too bad.
! 		 */
! 		if (PointerIsValid(portal->cleanup))
! 		{
! 			elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
! 			portal->cleanup = NULL;
! 		}
  
  		/* Zap it. */
  		PortalDrop(portal, false);
