agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v14 6/7] Restructure TupleTableSlot to allow tuples other than HeapTuple
114+ messages / 1 participants
[nested] [flat]

* [PATCH v14 6/7] Restructure TupleTableSlot to allow tuples other than HeapTuple
@ 2018-11-13 20:58 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2018-11-13 20:58 UTC (permalink / raw)

Author: Andres Freund and  Ashutosh Bapat, with changes by Amit Khandekar
Discussion: https://postgr.es/m/[email protected]
---
 src/backend/access/common/heaptuple.c  |  184 +--
 src/backend/catalog/index.c            |    4 +-
 src/backend/executor/execCurrent.c     |   18 +-
 src/backend/executor/execExpr.c        |    5 +-
 src/backend/executor/execExprInterp.c  |   13 +-
 src/backend/executor/execGrouping.c    |    5 +-
 src/backend/executor/execReplication.c |   41 +-
 src/backend/executor/execScan.c        |    4 +-
 src/backend/executor/execTuples.c      | 1665 ++++++++++++++++--------
 src/backend/executor/nodeAgg.c         |    5 +-
 src/backend/executor/nodeHashjoin.c    |   17 +-
 src/backend/executor/nodeModifyTable.c |   13 +
 src/backend/executor/nodeSubplan.c     |    1 +
 src/backend/jit/llvm/llvmjit.c         |    8 +-
 src/backend/jit/llvm/llvmjit_deform.c  |   52 +-
 src/backend/jit/llvm/llvmjit_expr.c    |    3 +-
 src/backend/jit/llvm/llvmjit_types.c   |    4 +-
 src/include/access/htup_details.h      |    2 -
 src/include/executor/executor.h        |    1 +
 src/include/executor/tuptable.h        |  305 ++++-
 src/include/jit/llvmjit.h              |    7 +-
 src/include/nodes/execnodes.h          |    1 +
 22 files changed, 1562 insertions(+), 796 deletions(-)

diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 28127b311f5..ccb69bdd616 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -71,6 +71,8 @@
 #define VARLENA_ATT_IS_PACKABLE(att) \
 	((att)->attstorage != 'p')
 
+static Datum getmissingattr(TupleDesc tupleDesc, int attnum, bool *isnull);
+
 
 /* ----------------------------------------------------------------
  *						misc support routines
@@ -80,7 +82,7 @@
 /*
  * Return the missing value of an attribute, or NULL if there isn't one.
  */
-Datum
+static Datum
 getmissingattr(TupleDesc tupleDesc,
 			   int attnum, bool *isnull)
 {
@@ -1350,186 +1352,6 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
 		values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]);
 }
 
-/*
- * slot_deform_tuple
- *		Given a TupleTableSlot, extract data from the slot's physical tuple
- *		into its Datum/isnull arrays.  Data is extracted up through the
- *		natts'th column (caller must ensure this is a legal column number).
- *
- *		This is essentially an incremental version of heap_deform_tuple:
- *		on each call we extract attributes up to the one needed, without
- *		re-computing information about previously extracted attributes.
- *		slot->tts_nvalid is the number of attributes already extracted.
- */
-void
-slot_deform_tuple(TupleTableSlot *slot, int natts)
-{
-	HeapTuple	tuple = slot->tts_tuple;
-	TupleDesc	tupleDesc = slot->tts_tupleDescriptor;
-	Datum	   *values = slot->tts_values;
-	bool	   *isnull = slot->tts_isnull;
-	HeapTupleHeader tup = tuple->t_data;
-	bool		hasnulls = HeapTupleHasNulls(tuple);
-	int			attnum;
-	char	   *tp;				/* ptr to tuple data */
-	uint32		off;			/* offset in tuple data */
-	bits8	   *bp = tup->t_bits;	/* ptr to null bitmap in tuple */
-	bool		slow;			/* can we use/set attcacheoff? */
-
-	/*
-	 * Check whether the first call for this tuple, and initialize or restore
-	 * loop state.
-	 */
-	attnum = slot->tts_nvalid;
-	if (attnum == 0)
-	{
-		/* Start from the first attribute */
-		off = 0;
-		slow = false;
-	}
-	else
-	{
-		/* Restore state from previous execution */
-		off = slot->tts_off;
-		slow = TTS_SLOW(slot);
-	}
-
-	tp = (char *) tup + tup->t_hoff;
-
-	for (; attnum < natts; attnum++)
-	{
-		Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
-
-		if (hasnulls && att_isnull(attnum, bp))
-		{
-			values[attnum] = (Datum) 0;
-			isnull[attnum] = true;
-			slow = true;		/* can't use attcacheoff anymore */
-			continue;
-		}
-
-		isnull[attnum] = false;
-
-		if (!slow && thisatt->attcacheoff >= 0)
-			off = thisatt->attcacheoff;
-		else if (thisatt->attlen == -1)
-		{
-			/*
-			 * We can only cache the offset for a varlena attribute if the
-			 * offset is already suitably aligned, so that there would be no
-			 * pad bytes in any case: then the offset will be valid for either
-			 * an aligned or unaligned value.
-			 */
-			if (!slow &&
-				off == att_align_nominal(off, thisatt->attalign))
-				thisatt->attcacheoff = off;
-			else
-			{
-				off = att_align_pointer(off, thisatt->attalign, -1,
-										tp + off);
-				slow = true;
-			}
-		}
-		else
-		{
-			/* not varlena, so safe to use att_align_nominal */
-			off = att_align_nominal(off, thisatt->attalign);
-
-			if (!slow)
-				thisatt->attcacheoff = off;
-		}
-
-		values[attnum] = fetchatt(thisatt, tp + off);
-
-		off = att_addlength_pointer(off, thisatt->attlen, tp + off);
-
-		if (thisatt->attlen <= 0)
-			slow = true;		/* can't use attcacheoff anymore */
-	}
-
-	/*
-	 * Save state for next execution
-	 */
-	slot->tts_nvalid = attnum;
-	slot->tts_off = off;
-	if (slow)
-		slot->tts_flags |= TTS_FLAG_SLOW;
-	else
-		slot->tts_flags &= ~TTS_FLAG_SLOW;
-}
-
-/*
- * slot_attisnull
- *		Detect whether an attribute of the slot is null, without
- *		actually fetching it.
- */
-bool
-slot_attisnull(TupleTableSlot *slot, int attnum)
-{
-	HeapTuple	tuple = slot->tts_tuple;
-	TupleDesc	tupleDesc = slot->tts_tupleDescriptor;
-
-	/*
-	 * system attributes are handled by heap_attisnull
-	 */
-	if (attnum <= 0)
-	{
-		if (tuple == NULL)		/* internal error */
-			elog(ERROR, "cannot extract system attribute from virtual tuple");
-		if (tuple == &(slot->tts_minhdr))	/* internal error */
-			elog(ERROR, "cannot extract system attribute from minimal tuple");
-		return heap_attisnull(tuple, attnum, tupleDesc);
-	}
-
-	/*
-	 * fast path if desired attribute already cached
-	 */
-	if (attnum <= slot->tts_nvalid)
-		return slot->tts_isnull[attnum - 1];
-
-	/*
-	 * return NULL if attnum is out of range according to the tupdesc
-	 */
-	if (attnum > tupleDesc->natts)
-		return true;
-
-	/*
-	 * otherwise we had better have a physical tuple (tts_nvalid should equal
-	 * natts in all virtual-tuple cases)
-	 */
-	if (tuple == NULL)			/* internal error */
-		elog(ERROR, "cannot extract attribute from empty tuple slot");
-
-	/* and let the tuple tell it */
-	return heap_attisnull(tuple, attnum, tupleDesc);
-}
-
-/*
- * slot_getsysattr
- *		This function fetches a system attribute of the slot's current tuple.
- *		Unlike slot_getattr, if the slot does not contain system attributes,
- *		this will return false (with a NULL attribute value) instead of
- *		throwing an error.
- */
-bool
-slot_getsysattr(TupleTableSlot *slot, int attnum,
-				Datum *value, bool *isnull)
-{
-	HeapTuple	tuple = slot->tts_tuple;
-
-	Assert(attnum < 0);			/* else caller error */
-	if (tuple == NULL ||
-		tuple == &(slot->tts_minhdr))
-	{
-		/* No physical tuple, or minimal tuple, so fail */
-		*value = (Datum) 0;
-		*isnull = true;
-		return false;
-	}
-	*value = heap_getsysattr(tuple, attnum, slot->tts_tupleDescriptor, isnull);
-	return true;
-}
-
 /*
  * heap_freetuple
  */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 21bdf794da6..a980202a7b1 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -2041,7 +2041,9 @@ FormIndexDatum(IndexInfo *indexInfo,
 		Datum		iDatum;
 		bool		isNull;
 
-		if (keycol != 0)
+		if (keycol < 0)
+			iDatum = slot_getsysattr(slot, keycol, &isNull);
+		else if (keycol != 0)
 		{
 			/*
 			 * Plain index column; get the value we need directly from the
diff --git a/src/backend/executor/execCurrent.c b/src/backend/executor/execCurrent.c
index aadf7493827..39c462a4e59 100644
--- a/src/backend/executor/execCurrent.c
+++ b/src/backend/executor/execCurrent.c
@@ -218,27 +218,25 @@ execCurrentOf(CurrentOfExpr *cexpr,
 			ItemPointer tuple_tid;
 
 #ifdef USE_ASSERT_CHECKING
-			if (!slot_getsysattr(scanstate->ss_ScanTupleSlot,
-								 TableOidAttributeNumber,
-								 &ldatum,
-								 &lisnull))
+			ldatum = slot_getsysattr(scanstate->ss_ScanTupleSlot,
+									 TableOidAttributeNumber,
+									 &lisnull);
+			if (lisnull)
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_CURSOR_STATE),
 						 errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"",
 								cursor_name, table_name)));
-			Assert(!lisnull);
 			Assert(DatumGetObjectId(ldatum) == table_oid);
 #endif
 
-			if (!slot_getsysattr(scanstate->ss_ScanTupleSlot,
-								 SelfItemPointerAttributeNumber,
-								 &ldatum,
-								 &lisnull))
+			ldatum = slot_getsysattr(scanstate->ss_ScanTupleSlot,
+									 SelfItemPointerAttributeNumber,
+									 &lisnull);
+			if (lisnull)
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_CURSOR_STATE),
 						 errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"",
 								cursor_name, table_name)));
-			Assert(!lisnull);
 			tuple_tid = (ItemPointer) DatumGetPointer(ldatum);
 
 			*current_tid = *tuple_tid;
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index a4099c23176..914d04186bd 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -3313,6 +3313,7 @@ ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
  */
 ExprState *
 ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
+					   const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
 					   int numCols,
 					   AttrNumber *keyColIdx,
 					   Oid *eqfunctions,
@@ -3354,7 +3355,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
 	scratch.d.fetch.last_var = maxatt;
 	scratch.d.fetch.fixed = false;
 	scratch.d.fetch.known_desc = ldesc;
-	scratch.d.fetch.kind = NULL;
+	scratch.d.fetch.kind = lops;
 	ExecComputeSlotInfo(state, &scratch);
 	ExprEvalPushStep(state, &scratch);
 
@@ -3362,7 +3363,7 @@ ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
 	scratch.d.fetch.last_var = maxatt;
 	scratch.d.fetch.fixed = false;
 	scratch.d.fetch.known_desc = rdesc;
-	scratch.d.fetch.kind = NULL;
+	scratch.d.fetch.kind = rops;
 	ExecComputeSlotInfo(state, &scratch);
 	ExprEvalPushStep(state, &scratch);
 
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 357eae41cc3..dbf2445a21d 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -428,7 +428,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 		{
 			CheckOpSlotCompatibility(op, innerslot);
 
-			/* XXX: worthwhile to check tts_nvalid inline first? */
 			slot_getsomeattrs(innerslot, op->d.fetch.last_var);
 
 			EEO_NEXT();
@@ -4026,15 +4025,15 @@ void
 ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
 			   TupleTableSlot *slot)
 {
-	bool success;
+	Datum d;
 
 	/* slot_getsysattr has sufficient defenses against bad attnums */
-	success = slot_getsysattr(slot,
-							  op->d.var.attnum,
-							  op->resvalue,
-							  op->resnull);
+	d = slot_getsysattr(slot,
+						op->d.var.attnum,
+						op->resnull);
+	*op->resvalue = d;
 	/* this ought to be unreachable, but it's cheap enough to check */
-	if (unlikely(!success))
+	if (unlikely(*op->resnull))
 		elog(ERROR, "failed to fetch attribute from slot");
 }
 
diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c
index 5bc200e4dc3..abce1e95cb6 100644
--- a/src/backend/executor/execGrouping.c
+++ b/src/backend/executor/execGrouping.c
@@ -75,7 +75,8 @@ execTuplesMatchPrepare(TupleDesc desc,
 		eqFunctions[i] = get_opcode(eqOperators[i]);
 
 	/* build actual expression */
-	expr = ExecBuildGroupingEqual(desc, desc, numCols, keyColIdx, eqFunctions,
+	expr = ExecBuildGroupingEqual(desc, desc, NULL, NULL,
+								  numCols, keyColIdx, eqFunctions,
 								  parent);
 
 	return expr;
@@ -206,7 +207,9 @@ BuildTupleHashTable(PlanState *parent,
 													&TTSOpsMinimalTuple);
 
 	/* build comparator for all columns */
+	/* XXX: should we support non-minimal tuples for the inputslot? */
 	hashtable->tab_eq_func = ExecBuildGroupingEqual(inputDesc, inputDesc,
+													&TTSOpsMinimalTuple, &TTSOpsMinimalTuple,
 													numCols,
 													keyColIdx, eqfuncoids,
 													parent);
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 071ba8762d4..727770eab56 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -170,8 +170,11 @@ retry:
 		HeapUpdateFailureData hufd;
 		HTSU_Result res;
 		HeapTupleData locktup;
+		HeapTupleTableSlot *hslot = (HeapTupleTableSlot *)outslot;
 
-		ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self);
+		/* Only a heap tuple has item pointers. */
+		Assert(TTS_IS_HEAPTUPLE(outslot) || TTS_IS_BUFFERTUPLE(outslot));
+		ItemPointerCopy(&hslot->tuple->t_self, &locktup.t_self);
 
 		PushActiveSnapshot(GetLatestSnapshot());
 
@@ -334,8 +337,12 @@ retry:
 		HeapUpdateFailureData hufd;
 		HTSU_Result res;
 		HeapTupleData locktup;
+		HeapTupleTableSlot *hslot = (HeapTupleTableSlot *)outslot;
 
-		ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self);
+		/* Only a heap tuple has item pointers. */
+		Assert(TTS_IS_HEAPTUPLE(outslot) || TTS_IS_BUFFERTUPLE(outslot));
+
+		ItemPointerCopy(&hslot->tuple->t_self, &locktup.t_self);
 
 		PushActiveSnapshot(GetLatestSnapshot());
 
@@ -456,6 +463,12 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
 	HeapTuple	tuple;
 	ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
 	Relation	rel = resultRelInfo->ri_RelationDesc;
+	HeapTupleTableSlot *hsearchslot = (HeapTupleTableSlot *)searchslot;
+	HeapTupleTableSlot *hslot = (HeapTupleTableSlot *)slot;
+
+	/* We expect both searchslot and the slot to contain a heap tuple. */
+	Assert(TTS_IS_HEAPTUPLE(searchslot) || TTS_IS_BUFFERTUPLE(searchslot));
+	Assert(TTS_IS_HEAPTUPLE(slot) || TTS_IS_BUFFERTUPLE(slot));
 
 	/* For now we support only tables. */
 	Assert(rel->rd_rel->relkind == RELKIND_RELATION);
@@ -467,8 +480,7 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
 		resultRelInfo->ri_TrigDesc->trig_update_before_row)
 	{
 		slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
-									&searchslot->tts_tuple->t_self,
-									NULL, slot);
+									&hsearchslot->tuple->t_self, NULL, slot);
 
 		if (slot == NULL)		/* "do nothing" */
 			skip_tuple = true;
@@ -488,19 +500,18 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
 		tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
 
 		/* OK, update the tuple and index entries for it */
-		simple_heap_update(rel, &searchslot->tts_tuple->t_self,
-						   slot->tts_tuple);
+		simple_heap_update(rel, &hsearchslot->tuple->t_self, hslot->tuple);
 
 		if (resultRelInfo->ri_NumIndices > 0 &&
-			!HeapTupleIsHeapOnly(slot->tts_tuple))
+			!HeapTupleIsHeapOnly(hslot->tuple))
 			recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
 												   estate, false, NULL,
 												   NIL);
 
 		/* AFTER ROW UPDATE Triggers */
 		ExecARUpdateTriggers(estate, resultRelInfo,
-							 &searchslot->tts_tuple->t_self,
-							 NULL, tuple, recheckIndexes, NULL);
+							 &hsearchslot->tuple->t_self, NULL, tuple,
+							 recheckIndexes, NULL);
 
 		list_free(recheckIndexes);
 	}
@@ -519,9 +530,11 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
 	bool		skip_tuple = false;
 	ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
 	Relation	rel = resultRelInfo->ri_RelationDesc;
+	HeapTupleTableSlot *hsearchslot = (HeapTupleTableSlot *)searchslot;
 
-	/* For now we support only tables. */
+	/* For now we support only tables and heap tuples. */
 	Assert(rel->rd_rel->relkind == RELKIND_RELATION);
+	Assert(TTS_IS_HEAPTUPLE(searchslot) || TTS_IS_BUFFERTUPLE(searchslot));
 
 	CheckCmdReplicaIdentity(rel, CMD_DELETE);
 
@@ -530,8 +543,8 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
 		resultRelInfo->ri_TrigDesc->trig_delete_before_row)
 	{
 		skip_tuple = !ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
-										   &searchslot->tts_tuple->t_self,
-										   NULL, NULL);
+										   &hsearchslot->tuple->t_self, NULL,
+										   NULL);
 	}
 
 	if (!skip_tuple)
@@ -539,11 +552,11 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
 		List	   *recheckIndexes = NIL;
 
 		/* OK, delete the tuple */
-		simple_heap_delete(rel, &searchslot->tts_tuple->t_self);
+		simple_heap_delete(rel, &hsearchslot->tuple->t_self);
 
 		/* AFTER ROW DELETE Triggers */
 		ExecARDeleteTriggers(estate, resultRelInfo,
-							 &searchslot->tts_tuple->t_self, NULL, NULL);
+							 &hsearchslot->tuple->t_self, NULL, NULL);
 
 		list_free(recheckIndexes);
 	}
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index 233cc280608..d90bb16b570 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -78,8 +78,8 @@ ExecScanFetch(ScanState *node,
 				return ExecClearTuple(slot);
 
 			/* Store test tuple in the plan node's scan slot */
-			ExecStoreHeapTuple(estate->es_epqTuple[scanrelid - 1],
-							   slot, false);
+			ExecForceStoreHeapTuple(estate->es_epqTuple[scanrelid - 1],
+									slot);
 
 			/* Check if it meets the access-method conditions */
 			if (!(*recheckMtd) (node, slot))
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index bb618e94f5d..bf49c4789cb 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -71,12 +71,1024 @@
 
 static TupleDesc ExecTypeFromTLInternal(List *targetList,
 					   bool hasoid, bool skipjunk);
+static void tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer);
 
 const TupleTableSlotOps TTSOpsVirtual;
 const TupleTableSlotOps TTSOpsHeapTuple;
 const TupleTableSlotOps TTSOpsMinimalTuple;
 const TupleTableSlotOps TTSOpsBufferTuple;
 
+/*
+ * slot_deform_heap_tuple
+ *		Given a TupleTableSlot, extract data from the slot's physical tuple
+ *		into its Datum/isnull arrays.  Data is extracted up through the
+ *		natts'th column (caller must ensure this is a legal column number).
+ *
+ *		This is essentially an incremental version of heap_deform_tuple:
+ *		on each call we extract attributes up to the one needed, without
+ *		re-computing information about previously extracted attributes.
+ *		slot->tts_nvalid is the number of attributes already extracted.
+ */
+static inline void __attribute__((always_inline))
+slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
+					   int natts)
+{
+	TupleDesc	tupleDesc = slot->tts_tupleDescriptor;
+	Datum	   *values = slot->tts_values;
+	bool	   *isnull = slot->tts_isnull;
+	HeapTupleHeader tup = tuple->t_data;
+	bool		hasnulls = HeapTupleHasNulls(tuple);
+	int			attnum;
+	char	   *tp;				/* ptr to tuple data */
+	uint32		off;			/* offset in tuple data */
+	bits8	   *bp = tup->t_bits;	/* ptr to null bitmap in tuple */
+	bool		slow;			/* can we use/set attcacheoff? */
+
+	/* We can only fetch as many attributes as the tuple has. */
+	natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts);
+
+	/*
+	 * Check whether the first call for this tuple, and initialize or restore
+	 * loop state.
+	 */
+	attnum = slot->tts_nvalid;
+	if (attnum == 0)
+	{
+		/* Start from the first attribute */
+		off = 0;
+		slow = false;
+	}
+	else
+	{
+		/* Restore state from previous execution */
+		off = *offp;
+		slow = TTS_SLOW(slot);
+	}
+
+	tp = (char *) tup + tup->t_hoff;
+
+	for (; attnum < natts; attnum++)
+	{
+		Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
+
+		if (hasnulls && att_isnull(attnum, bp))
+		{
+			values[attnum] = (Datum) 0;
+			isnull[attnum] = true;
+			slow = true;		/* can't use attcacheoff anymore */
+			continue;
+		}
+
+		isnull[attnum] = false;
+
+		if (!slow && thisatt->attcacheoff >= 0)
+			off = thisatt->attcacheoff;
+		else if (thisatt->attlen == -1)
+		{
+			/*
+			 * We can only cache the offset for a varlena attribute if the
+			 * offset is already suitably aligned, so that there would be no
+			 * pad bytes in any case: then the offset will be valid for either
+			 * an aligned or unaligned value.
+			 */
+			if (!slow &&
+				off == att_align_nominal(off, thisatt->attalign))
+				thisatt->attcacheoff = off;
+			else
+			{
+				off = att_align_pointer(off, thisatt->attalign, -1,
+										tp + off);
+				slow = true;
+			}
+		}
+		else
+		{
+			/* not varlena, so safe to use att_align_nominal */
+			off = att_align_nominal(off, thisatt->attalign);
+
+			if (!slow)
+				thisatt->attcacheoff = off;
+		}
+
+		values[attnum] = fetchatt(thisatt, tp + off);
+
+		off = att_addlength_pointer(off, thisatt->attlen, tp + off);
+
+		if (thisatt->attlen <= 0)
+			slow = true;		/* can't use attcacheoff anymore */
+	}
+
+	/*
+	 * Save state for next execution
+	 */
+	slot->tts_nvalid = attnum;
+	*offp = off;
+	if (slow)
+		slot->tts_flags |= TTS_FLAG_SLOW;
+	else
+		slot->tts_flags &= ~TTS_FLAG_SLOW;
+}
+
+/*
+ * TupleTableSlotOps implementations.
+ */
+
+/*
+ * TupleTableSlotOps implementation for VirtualTupleTableSlot.
+ */
+static void
+tts_virtual_init(TupleTableSlot *slot)
+{
+}
+
+static void
+tts_virtual_release(TupleTableSlot *slot)
+{
+}
+
+static void
+tts_virtual_clear(TupleTableSlot *slot)
+{
+	if (unlikely(TTS_SHOULDFREE(slot)))
+	{
+		VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
+
+		pfree(vslot->data);
+		vslot->data = NULL;
+
+		slot->tts_flags = ~TTS_FLAG_SHOULDFREE;
+	}
+
+	slot->tts_nvalid = 0;
+	slot->tts_flags |= TTS_FLAG_EMPTY;
+}
+
+/*
+ * Attribute values are readily available in tts_values and tts_isnull array
+ * in a VirtualTupleTableSlot. So there should be no need to call either of the
+ * following two functions.
+ */
+static void
+tts_virtual_getsomeattrs(TupleTableSlot *slot, int natts)
+{
+	elog(ERROR, "getsomeattrs is not required to be called on a virtual tuple table slot");
+}
+
+static Datum
+tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
+{
+	elog(ERROR, "virtual tuple table slot does not have system atttributes");
+}
+
+/*
+ * To materialize a virtual slot all the datums that aren't passed by value
+ * have to be copied into the slot's memory context.  To do so, count the
+ * required size, and allocate enough memory to store all attributes.  That
+ * both gains efficiency, and makes it easier to release all the memory at
+ * once.
+ */
+static void
+tts_virtual_materialize(TupleTableSlot *slot)
+{
+	VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
+	TupleDesc	desc = slot->tts_tupleDescriptor;
+	Size		sz = 0;
+	char	   *data;
+
+	/* already materialized */
+	if (TTS_SHOULDFREE(slot))
+		return;
+
+	/* compute size of memory required */
+	for (int natt = 0; natt < desc->natts; natt++)
+	{
+		Form_pg_attribute att = TupleDescAttr(desc, natt);
+		Datum val;
+
+		if (att->attbyval || slot->tts_isnull[natt])
+			continue;
+
+		val = slot->tts_values[natt];
+
+		if (att->attlen == -1 &&
+			VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
+		{
+			/*
+			 * We want to flatten the expanded value so that the materialized
+			 * slot doesn't depend on it.
+			 */
+			sz = att_align_nominal(sz, att->attalign);
+			sz += EOH_get_flat_size(DatumGetEOHP(val));
+		}
+		else
+		{
+			sz = att_align_nominal(sz, att->attalign);
+			sz = att_addlength_datum(sz, att->attlen, val);
+		}
+
+		/* FIXME: any reason to expand default args? */
+	}
+
+	/* all data is byval */
+	if (sz == 0)
+		return;
+
+	/* allocate memory */
+	vslot->data = data = MemoryContextAlloc(slot->tts_mcxt, sz);
+	slot->tts_flags |= TTS_FLAG_SHOULDFREE;
+
+	/* and copy all attributes into the pre-allocated space */
+	for (int natt = 0; natt < desc->natts; natt++)
+	{
+		Form_pg_attribute att = TupleDescAttr(desc, natt);
+		Datum val;
+
+		if (att->attbyval || slot->tts_isnull[natt])
+			continue;
+
+		val = slot->tts_values[natt];
+
+		if (att->attlen == -1 &&
+			VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
+		{
+			Size data_length;
+
+			/*
+			 * We want to flatten the expanded value so that the materialized
+			 * slot doesn't depend on it.
+			 */
+			ExpandedObjectHeader *eoh = DatumGetEOHP(val);
+
+			data = (char *) att_align_nominal(data,
+											  att->attalign);
+			data_length = EOH_get_flat_size(eoh);
+			EOH_flatten_into(eoh, data, data_length);
+
+			slot->tts_values[natt] = PointerGetDatum(data);
+			data += data_length;
+		}
+		else
+		{
+			Size data_length = 0;
+
+			data = (char *) att_align_nominal(data, att->attalign);
+			data_length = att_addlength_datum(data_length, att->attlen, val);
+
+			memcpy(data, DatumGetPointer(val), data_length);
+
+			slot->tts_values[natt] = PointerGetDatum(data);
+			data += data_length;
+		}
+		/* FIXME: any reason to expand default args? */
+	}
+}
+
+/*
+ * A virtual tuple table slot can not copy the datums into its own storage. So
+ * it can not copy contents of the other slot into its own memory context.
+ */
+static void
+tts_virtual_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
+{
+	TupleDesc	srcdesc = dstslot->tts_tupleDescriptor;
+
+	Assert(srcdesc->natts <= dstslot->tts_tupleDescriptor->natts);
+
+	tts_virtual_clear(dstslot);
+
+	slot_getallattrs(srcslot);
+
+	for (int natt = 0; natt < srcdesc->natts; natt++)
+	{
+		dstslot->tts_values[natt] = srcslot->tts_values[natt];
+		dstslot->tts_isnull[natt] = srcslot->tts_isnull[natt];
+	}
+
+	dstslot->tts_nvalid = srcdesc->natts;
+	dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
+
+	/* make sure storage doesn't depend on external memory */
+	tts_virtual_materialize(dstslot);
+}
+
+static HeapTuple
+tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
+{
+	Assert(!TTS_EMPTY(slot));
+
+	return heap_form_tuple(slot->tts_tupleDescriptor,
+						   slot->tts_values,
+						   slot->tts_isnull);
+
+}
+
+static MinimalTuple
+tts_virtual_copy_minimal_tuple(TupleTableSlot *slot)
+{
+	Assert(!TTS_EMPTY(slot));
+
+	return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
+								   slot->tts_values,
+								   slot->tts_isnull);
+}
+
+/*
+ * TupleTableSlotOps implementation for HeapTupleTableSlot.
+ */
+
+static void
+tts_heap_init(TupleTableSlot *slot)
+{
+}
+
+static void
+tts_heap_release(TupleTableSlot *slot)
+{
+}
+
+static void
+tts_heap_clear(TupleTableSlot *slot)
+{
+	HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+
+	/* Free the memory for the heap tuple if it's allowed. */
+	if (TTS_SHOULDFREE(slot))
+	{
+		heap_freetuple(hslot->tuple);
+		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
+	}
+
+	slot->tts_nvalid = 0;
+	slot->tts_flags |= TTS_FLAG_EMPTY;
+	hslot->off = 0;
+	hslot->tuple = NULL;
+}
+
+static void
+tts_heap_getsomeattrs(TupleTableSlot *slot, int natts)
+{
+	HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+
+	Assert(!TTS_EMPTY(slot));
+
+	slot_deform_heap_tuple(slot, hslot->tuple, &hslot->off, natts);
+}
+
+static Datum
+tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
+{
+	HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+
+	return heap_getsysattr(hslot->tuple, attnum,
+						   slot->tts_tupleDescriptor, isnull);
+}
+
+/*
+ * Materialize the heap tuple contained in the given slot into its own memory
+ * context.
+ */
+static void
+tts_heap_materialize(TupleTableSlot *slot)
+{
+	HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+	MemoryContext oldContext;
+
+	Assert(!TTS_EMPTY(slot));
+
+	/* This slot has it's tuple already materialized. Nothing to do. */
+	if (TTS_SHOULDFREE(slot))
+		return;
+
+	slot->tts_flags |= TTS_FLAG_SHOULDFREE;
+
+	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
+
+	if (!hslot->tuple)
+		hslot->tuple = heap_form_tuple(slot->tts_tupleDescriptor,
+									   slot->tts_values,
+									   slot->tts_isnull);
+	else
+	{
+		/*
+		 * The tuple contained in this slot is not allocated in the memory
+		 * context of the given slot (else it would have TTS_SHOULDFREE set).
+		 * Copy the tuple into the given slot's memory context.
+		 */
+		hslot->tuple = heap_copytuple(hslot->tuple);
+	}
+
+	slot->tts_nvalid = 0;
+	hslot->off = 0;
+
+	MemoryContextSwitchTo(oldContext);
+}
+
+/*
+ * Copy contents of the srcslot into dstslot, on which this callback has been
+ * invoked, in dstslot's memory context. We do this by creating a heap tuple
+ * from the source slot's contents in the memory context of the destination
+ * slot and then storing that heap tuple in the destination slot.
+ */
+static void
+tts_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
+{
+	HeapTuple tuple;
+	MemoryContext oldcontext;
+
+	oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
+	tuple = ExecCopySlotTuple(srcslot);
+	MemoryContextSwitchTo(oldcontext);
+
+	ExecStoreHeapTuple(tuple, dstslot, true);
+}
+
+/*
+ * Return the heap tuple in the slot as is if it contains one. Otherwise,
+ * materialize a heap tuple using contents of the slot and return it.
+ */
+static HeapTuple
+tts_heap_get_heap_tuple(TupleTableSlot *slot)
+{
+	HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+
+	Assert(!TTS_EMPTY(slot));
+	if (!hslot->tuple)
+		tts_heap_materialize(slot);
+
+	return hslot->tuple;
+}
+
+/*
+ * Return a copy of heap tuple contained in the slot, materialising one if
+ * necessary.
+ */
+static HeapTuple
+tts_heap_copy_heap_tuple(TupleTableSlot *slot)
+{
+	HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+
+	Assert(!TTS_EMPTY(slot));
+	if (!hslot->tuple)
+		tts_heap_materialize(slot);
+
+	return heap_copytuple(hslot->tuple);
+}
+
+/*
+ * Return a minimal tuple constructed from the contents of the slot.
+ *
+ * We always return a new minimal tuple so no copy, per say, is needed.
+ */
+static MinimalTuple
+tts_heap_copy_minimal_tuple(TupleTableSlot *slot)
+{
+	HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+
+	if (!hslot->tuple)
+		tts_heap_materialize(slot);
+
+	return minimal_tuple_from_heap_tuple(hslot->tuple);
+}
+
+/*
+ * Store the given tuple into the given HeapTupleTableSlot. If the slot
+ * already contains a tuple, we will free the memory for the same before
+ * storing a new one there.
+ */
+static void
+tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
+{
+	HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+
+	tts_heap_clear(slot);
+
+	slot->tts_nvalid = 0;
+	hslot->tuple = tuple;
+	hslot->off = 0;
+	slot->tts_flags &= ~TTS_FLAG_EMPTY;
+
+	if (shouldFree)
+		slot->tts_flags |= TTS_FLAG_SHOULDFREE;
+}
+
+
+static void
+tts_minimal_init(TupleTableSlot *slot)
+{
+	MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
+
+	/*
+	 * Initialize the heap tuple pointer to access attributes of the minimal
+	 * tuple contained in the slot as if its a heap tuple.
+	 */
+	mslot->tuple = &mslot->minhdr;
+}
+
+static void
+tts_minimal_release(TupleTableSlot *slot)
+{
+}
+
+static void
+tts_minimal_clear(TupleTableSlot *slot)
+{
+	MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
+
+	if (TTS_SHOULDFREE(slot))
+	{
+		heap_free_minimal_tuple(mslot->mintuple);
+		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
+	}
+
+	slot->tts_nvalid = 0;
+	slot->tts_flags |= TTS_FLAG_EMPTY;
+	mslot->off = 0;
+	mslot->mintuple = NULL;
+}
+
+static void
+tts_minimal_getsomeattrs(TupleTableSlot *slot, int natts)
+{
+	MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
+
+	Assert(!TTS_EMPTY(slot));
+
+	slot_deform_heap_tuple(slot, mslot->tuple, &mslot->off, natts);
+}
+
+static Datum
+tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
+{
+	elog(ERROR, "minimal tuple table slot does not have system atttributes");
+}
+
+/*
+ * Materialize the minimal tuple contained in the given slot into its own
+ * memory context.
+ */
+static void
+tts_minimal_materialize(TupleTableSlot *slot)
+{
+	MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
+	MemoryContext oldContext;
+
+	Assert(!TTS_EMPTY(slot));
+
+	/* This slot has it's tuple already materialized. Nothing to do. */
+	if (TTS_SHOULDFREE(slot))
+		return;
+
+	slot->tts_flags |= TTS_FLAG_SHOULDFREE;
+	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
+
+	if (!mslot->mintuple)
+		mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
+												  slot->tts_values,
+												  slot->tts_isnull);
+	else
+	{
+		/*
+		 * The minimal tuple contained in this slot is not allocated in the
+		 * memory context of the given slot (else it would have TTS_SHOULDFREE
+		 * set).  Copy the minimal tuple into the given slot's memory context.
+		 */
+		mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple);
+	}
+
+	Assert(mslot->tuple == &mslot->minhdr);
+
+	mslot->minhdr.t_len = mslot->mintuple->t_len + MINIMAL_TUPLE_OFFSET;
+	mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mslot->mintuple - MINIMAL_TUPLE_OFFSET);
+
+	MemoryContextSwitchTo(oldContext);
+
+	slot->tts_nvalid = 0;
+	mslot->off = 0;
+}
+
+/*
+ * Copy contents of the srcslot into dstslot, on which this callback has been
+ * invoked, in dstslot's memory context. We do this by creating a minimal tuple
+ * from the source slot's contents in the memory context of the destination
+ * slot and then storing that minimal tuple in the destination slot.
+ */
+static void
+tts_minimal_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
+{
+	MemoryContext oldcontext;
+	MinimalTuple mintuple;
+
+	oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
+	mintuple = ExecCopySlotMinimalTuple(srcslot);
+	MemoryContextSwitchTo(oldcontext);
+
+	ExecStoreMinimalTuple(mintuple, dstslot, true);
+}
+
+/*
+ * Return the minimal tuple if slot contains one. Otherwise materialize the
+ * contents of slot into a minimal tuple and return that.
+ */
+static MinimalTuple
+tts_minimal_get_minimal_tuple(TupleTableSlot *slot)
+{
+	MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
+
+	Assert(!TTS_EMPTY(slot));
+
+	if (!mslot->mintuple)
+		tts_minimal_materialize(slot);
+
+	return mslot->mintuple;
+}
+
+/*
+ * Return a heap tuple constructed from the minimal tuple contained in the slot.
+ *
+ * We always construct a new heap tuple, so there is nothing to copy as such.
+ */
+static HeapTuple
+tts_minimal_copy_heap_tuple(TupleTableSlot *slot)
+{
+	MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
+
+	/* Materialize the minimal tuple if not already present. */
+	if (!mslot->mintuple)
+		tts_minimal_materialize(slot);
+
+	return heap_tuple_from_minimal_tuple(mslot->mintuple);
+}
+
+/*
+ * Return a copy of minimal tuple contained in the slot, materializing one if
+ * necessary.
+ */
+static MinimalTuple
+tts_minimal_copy_minimal_tuple(TupleTableSlot *slot)
+{
+	MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
+
+	if (!mslot->mintuple)
+		tts_minimal_materialize(slot);
+
+	return heap_copy_minimal_tuple(mslot->mintuple);
+}
+
+/*
+ * Store the given minimal tuple into the given MinimalTupleTableSlot. If the
+ * slot already contains a tuple, we will free the memory for the same before
+ * storing a new one there.
+ */
+static void
+tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree)
+{
+	MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
+
+	tts_minimal_clear(slot);
+
+	Assert(!TTS_SHOULDFREE(slot));
+	Assert(TTS_EMPTY(slot));
+
+	slot->tts_flags &= ~TTS_FLAG_EMPTY;
+	slot->tts_nvalid = 0;
+	mslot->off = 0;
+
+	mslot->mintuple = mtup;
+	Assert(mslot->tuple == &mslot->minhdr);
+	mslot->minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
+	mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
+	/* no need to set t_self or t_tableOid since we won't allow access */
+
+	if (shouldFree)
+		slot->tts_flags |= TTS_FLAG_SHOULDFREE;
+	else
+		Assert(!TTS_SHOULDFREE(slot));
+}
+
+/*
+ * TupleTableSlotOps implementation for BufferHeapTupleTableSlot.
+ */
+
+static void
+tts_buffer_heap_init(TupleTableSlot *slot)
+{
+}
+
+static void
+tts_buffer_heap_release(TupleTableSlot *slot)
+{
+}
+
+static void
+tts_buffer_heap_clear(TupleTableSlot *slot)
+{
+	BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+
+	/*
+	 * Free the memory for heap tuple if allowed. A tuple coming from buffer
+	 * can never be freed. But we may have materialized a tuple from buffer.
+	 * Such a tuple can be freed.
+	 */
+	if (TTS_SHOULDFREE(slot))
+	{
+		/* We should have unpinned the buffer while materializing the tuple. */
+		Assert(!BufferIsValid(bslot->buffer));
+
+		heap_freetuple(bslot->base.tuple);
+		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
+
+		Assert(!BufferIsValid(bslot->buffer));
+	}
+
+	if (BufferIsValid(bslot->buffer))
+		ReleaseBuffer(bslot->buffer);
+
+	slot->tts_nvalid = 0;
+	slot->tts_flags |= TTS_FLAG_EMPTY;
+	bslot->base.tuple = NULL;
+	bslot->base.off = 0;
+	bslot->buffer = InvalidBuffer;
+}
+
+static void
+tts_buffer_heap_getsomeattrs(TupleTableSlot *slot, int natts)
+{
+	BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+
+	Assert(!TTS_EMPTY(slot));
+
+	slot_deform_heap_tuple(slot, bslot->base.tuple, &bslot->base.off, natts);
+}
+
+static Datum
+tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
+{
+	BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+
+	return heap_getsysattr(bslot->base.tuple, attnum,
+						   slot->tts_tupleDescriptor, isnull);
+}
+
+/*
+ * Materialize the heap tuple contained in the given slot into its own memory
+ * context.
+ */
+static void
+tts_buffer_heap_materialize(TupleTableSlot *slot)
+{
+	BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+	MemoryContext oldContext;
+
+	Assert(!TTS_EMPTY(slot));
+
+	/* If already materialized nothing to do. */
+	if (TTS_SHOULDFREE(slot))
+		return;
+
+	slot->tts_flags |= TTS_FLAG_SHOULDFREE;
+	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
+
+	if (!bslot->base.tuple)
+	{
+		/*
+		 * A heap tuple stored in a BufferHeapTupleTableSlot should have a
+		 * buffer associated with it, unless it's materialized. Thus it will
+		 * never happen that there is no heap tuple stored in this slot but
+		 * tts_values and tts_isnull is set. IOW, we should never require to construct a
+		 * tuple from tts_values and tts_isnull in this slot.
+		 */
+		elog(ERROR, "a buffer tuple table slot should never require to construct a tuple from datums");
+	}
+	bslot->base.tuple = heap_copytuple(bslot->base.tuple);
+	MemoryContextSwitchTo(oldContext);
+
+	/*
+	 * A heap tuple stored in a BufferHeapTupleTableSlot should have a buffer
+	 * associated with it, unless it's materialized.
+	 */
+	Assert(BufferIsValid(bslot->buffer));
+	ReleaseBuffer(bslot->buffer);
+	bslot->buffer = InvalidBuffer;
+
+	bslot->base.off = 0;
+	slot->tts_nvalid = 0;
+}
+
+/*
+ * A buffer tuple table slot is used to store an on-disk tuple in it, at least
+ * to start with. So a need to copy into a buffer tuple table slot should not
+ * arise. May be we could support copying from a buffer tuple table slot, but
+ * it is not clear why it's required to do that.
+ */
+static void
+tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
+{
+	BufferHeapTupleTableSlot *bsrcslot = (BufferHeapTupleTableSlot *) srcslot;
+	BufferHeapTupleTableSlot *bdstslot = (BufferHeapTupleTableSlot *) dstslot;
+
+	Assert(dstslot->tts_cb == srcslot->tts_cb);
+
+	if (TTS_SHOULDFREE(srcslot))
+	{
+		MemoryContext oldContext;
+
+		ExecClearTuple(dstslot);
+		dstslot->tts_flags |= TTS_FLAG_SHOULDFREE;
+		dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
+		oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
+		bdstslot->base.tuple = heap_copytuple(bsrcslot->base.tuple);
+		MemoryContextSwitchTo(oldContext);
+	}
+	else
+	{
+		tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple, bsrcslot->buffer);
+		tts_buffer_heap_materialize(dstslot);
+	}
+}
+
+/*
+ * Return the heap tuple in the slot as is if it contains one. Otherwise,
+ * materialize a heap tuple using contents of the slot and return it.
+ */
+static HeapTuple
+tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
+{
+	BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+
+	Assert(!TTS_EMPTY(slot));
+
+	/* Is this even possible for a buffer tuple? */
+	if (!bslot->base.tuple)
+		tts_buffer_heap_materialize(slot);
+
+	return bslot->base.tuple;
+}
+
+/*
+ * Return a copy of heap tuple contained in the slot, materialising one if
+ * necessary.
+ */
+static HeapTuple
+tts_buffer_heap_copy_heap_tuple(TupleTableSlot *slot)
+{
+	BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+
+	Assert(!TTS_EMPTY(slot));
+
+	/* Is this even possible for a buffer tuple? */
+	if (!bslot->base.tuple)
+		tts_buffer_heap_materialize(slot);
+
+	return heap_copytuple(bslot->base.tuple);
+}
+
+/*
+ * Return a minimal tuple constructed from the contents of the slot.
+ *
+ * We always return a new minimal tuple so no copy, per say, is needed.
+ */
+static MinimalTuple
+tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
+{
+	BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+
+	Assert(!TTS_EMPTY(slot));
+
+	/* Is this even possible for a buffer tuple? */
+	if (!bslot->base.tuple)
+		tts_buffer_heap_materialize(slot);
+
+	return minimal_tuple_from_heap_tuple(bslot->base.tuple);
+}
+
+/*
+ * Store the given tuple into the given BufferHeapTupleTableSlot and pin the
+ * given buffer. If the tuple already contained in the slot can be freed free
+ * it.
+ */
+static void
+tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer)
+{
+	BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+
+	if (TTS_SHOULDFREE(slot))
+	{
+		/*
+		 * A heap tuple stored in a BufferHeapTupleTableSlot should have a
+		 * buffer associated with it, unless it's materialized.
+		 */
+		Assert(!BufferIsValid(bslot->buffer));
+
+		heap_freetuple(bslot->base.tuple);
+		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
+	}
+
+	slot->tts_flags &= ~TTS_FLAG_EMPTY;
+	slot->tts_nvalid = 0;
+	bslot->base.tuple = tuple;
+	bslot->base.off = 0;
+
+	/*
+	 * If tuple is on a disk page, keep the page pinned as long as we hold a
+	 * pointer into it.  We assume the caller already has such a pin.
+	 *
+	 * This is coded to optimize the case where the slot previously held a
+	 * tuple on the same disk page: in that case releasing and re-acquiring
+	 * the pin is a waste of cycles.  This is a common situation during
+	 * seqscans, so it's worth troubling over.
+	 */
+	if (bslot->buffer != buffer)
+	{
+		if (BufferIsValid(bslot->buffer))
+			ReleaseBuffer(bslot->buffer);
+		bslot->buffer = buffer;
+		IncrBufferRefCount(buffer);
+	}
+}
+
+/*
+ * TupleTableSlotOps for each of TupleTableSlotTypes. These are used to
+ * identify the type of slot.
+ */
+const TupleTableSlotOps TTSOpsVirtual = {
+	.base_slot_size = sizeof(VirtualTupleTableSlot),
+	.init = tts_virtual_init,
+	.release = tts_virtual_release,
+	.clear = tts_virtual_clear,
+	.getsomeattrs = tts_virtual_getsomeattrs,
+	.getsysattr = tts_virtual_getsysattr,
+	.materialize = tts_virtual_materialize,
+	.copyslot = tts_virtual_copyslot,
+
+	/*
+	 * A virtual tuple table slot can not "own" a heap tuple or a minimal
+	 * tuple.
+	 */
+	.get_heap_tuple = NULL,
+	.get_minimal_tuple = NULL,
+	.copy_heap_tuple = tts_virtual_copy_heap_tuple,
+	.copy_minimal_tuple = tts_virtual_copy_minimal_tuple
+};
+
+const TupleTableSlotOps TTSOpsHeapTuple = {
+	.base_slot_size = sizeof(HeapTupleTableSlot),
+	.init = tts_heap_init,
+	.release = tts_heap_release,
+	.clear = tts_heap_clear,
+	.getsomeattrs = tts_heap_getsomeattrs,
+	.getsysattr = tts_heap_getsysattr,
+	.materialize = tts_heap_materialize,
+	.copyslot = tts_heap_copyslot,
+	.get_heap_tuple = tts_heap_get_heap_tuple,
+
+	/* A heap tuple table slot can not "own" a minimal tuple. */
+	.get_minimal_tuple = NULL,
+	.copy_heap_tuple = tts_heap_copy_heap_tuple,
+	.copy_minimal_tuple = tts_heap_copy_minimal_tuple
+};
+
+const TupleTableSlotOps TTSOpsMinimalTuple = {
+	.base_slot_size = sizeof(MinimalTupleTableSlot),
+	.init = tts_minimal_init,
+	.release = tts_minimal_release,
+	.clear = tts_minimal_clear,
+	.getsomeattrs = tts_minimal_getsomeattrs,
+	.getsysattr = tts_minimal_getsysattr,
+	.materialize = tts_minimal_materialize,
+	.copyslot = tts_minimal_copyslot,
+
+	/*
+	 * A minimal tuple table slot can not "own" a heap tuple. As mentioned in
+	 * the prologue of MinimalTupleData, a minimal tuple may be presented as a
+	 * heap tuple, but such a representation does not have memory to hold
+	 * system attributes in it and should be used for accessing/manipulating
+	 * tuple through a slot. Hence we do not return heap tuple representation
+	 * crafted from a minimal tuple to be returned in get_heap_tuple callback
+	 * of this TupleTableSlotType.
+	 */
+	.get_heap_tuple = NULL,
+	.get_minimal_tuple = tts_minimal_get_minimal_tuple,
+	.copy_heap_tuple = tts_minimal_copy_heap_tuple,
+	.copy_minimal_tuple = tts_minimal_copy_minimal_tuple
+};
+
+const TupleTableSlotOps TTSOpsBufferTuple = {
+	.base_slot_size = sizeof(BufferHeapTupleTableSlot),
+	.init = tts_buffer_heap_init,
+	.release = tts_buffer_heap_release,
+	.clear = tts_buffer_heap_clear,
+	.getsomeattrs = tts_buffer_heap_getsomeattrs,
+	.getsysattr = tts_buffer_heap_getsysattr,
+	.materialize = tts_buffer_heap_materialize,
+	.copyslot = tts_buffer_heap_copyslot,
+	.get_heap_tuple = tts_buffer_heap_get_heap_tuple,
+
+	/* A buffer heap tuple table slot can not "own" a minimal tuple. */
+	.get_minimal_tuple = NULL,
+	.copy_heap_tuple = tts_buffer_heap_copy_heap_tuple,
+	.copy_minimal_tuple = tts_buffer_heap_copy_minimal_tuple
+};
+
 /* ----------------------------------------------------------------
  *				  tuple table create/delete functions
  * ----------------------------------------------------------------
@@ -85,58 +1097,60 @@ const TupleTableSlotOps TTSOpsBufferTuple;
 /* --------------------------------
  *		MakeTupleTableSlot
  *
- *		Basic routine to make an empty TupleTableSlot. If tupleDesc is
- *		specified the slot's descriptor is fixed for it's lifetime, gaining
- *		some efficiency. If that's undesirable, pass NULL.
+ *		Basic routine to make an empty TupleTableSlot of given
+ *		TupleTableSlotType. If tupleDesc is specified the slot's descriptor is
+ *		fixed for it's lifetime, gaining some efficiency. If that's
+ *		undesirable, pass NULL.
  * --------------------------------
  */
 TupleTableSlot *
 MakeTupleTableSlot(TupleDesc tupleDesc,
 				   const TupleTableSlotOps *tts_cb)
 {
-	Size		sz;
+	Size		basesz, allocsz;
 	TupleTableSlot *slot;
+	basesz = tts_cb->base_slot_size;
 
 	/*
 	 * When a fixed descriptor is specified, we can reduce overhead by
 	 * allocating the entire slot in one go.
 	 */
 	if (tupleDesc)
-		sz = MAXALIGN(sizeof(TupleTableSlot)) +
+		allocsz = MAXALIGN(basesz) +
 			MAXALIGN(tupleDesc->natts * sizeof(Datum)) +
 			MAXALIGN(tupleDesc->natts * sizeof(bool));
 	else
-		sz = sizeof(TupleTableSlot);
+		allocsz = basesz;
 
-	slot = palloc0(sz);
+	slot = palloc0(allocsz);
 	/* const for optimization purposes, OK to modify at allocation time */
 	*((const TupleTableSlotOps **) &slot->tts_cb) = tts_cb;
 	slot->type = T_TupleTableSlot;
 	slot->tts_flags |= TTS_FLAG_EMPTY;
 	if (tupleDesc != NULL)
 		slot->tts_flags |= TTS_FLAG_FIXED;
-	slot->tts_tuple = NULL;
 	slot->tts_tupleDescriptor = tupleDesc;
 	slot->tts_mcxt = CurrentMemoryContext;
-	slot->tts_buffer = InvalidBuffer;
 	slot->tts_nvalid = 0;
-	slot->tts_values = NULL;
-	slot->tts_isnull = NULL;
-	slot->tts_mintuple = NULL;
 
 	if (tupleDesc != NULL)
 	{
 		slot->tts_values = (Datum *)
 			(((char *) slot)
-			 + MAXALIGN(sizeof(TupleTableSlot)));
+			 + MAXALIGN(basesz));
 		slot->tts_isnull = (bool *)
 			(((char *) slot)
-			 + MAXALIGN(sizeof(TupleTableSlot))
+			 + MAXALIGN(basesz)
 			 + MAXALIGN(tupleDesc->natts * sizeof(Datum)));
 
 		PinTupleDesc(tupleDesc);
 	}
 
+	/*
+	 * And allow slot type specific initialization.
+	 */
+	slot->tts_cb->init(slot);
+
 	return slot;
 }
 
@@ -178,6 +1192,7 @@ ExecResetTupleTable(List *tupleTable,	/* tuple table */
 
 		/* Always release resources and reset the slot to empty */
 		ExecClearTuple(slot);
+		slot->tts_cb->release(slot);
 		if (slot->tts_tupleDescriptor)
 		{
 			ReleaseTupleDesc(slot->tts_tupleDescriptor);
@@ -234,6 +1249,7 @@ ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
 	/* This should match ExecResetTupleTable's processing of one slot */
 	Assert(IsA(slot, TupleTableSlot));
 	ExecClearTuple(slot);
+	slot->tts_cb->release(slot);
 	if (slot->tts_tupleDescriptor)
 		ReleaseTupleDesc(slot->tts_tupleDescriptor);
 	if (!TTS_FIXED(slot))
@@ -334,36 +1350,9 @@ ExecStoreHeapTuple(HeapTuple tuple,
 	Assert(slot != NULL);
 	Assert(slot->tts_tupleDescriptor != NULL);
 
-	/*
-	 * Free any old physical tuple belonging to the slot.
-	 */
-	if (TTS_SHOULDFREE(slot))
-	{
-		heap_freetuple(slot->tts_tuple);
-		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
-	}
-	if (TTS_SHOULDFREEMIN(slot))
-	{
-		heap_free_minimal_tuple(slot->tts_mintuple);
-		slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
-	}
-
-	/*
-	 * Store the new tuple into the specified slot.
-	 */
-	slot->tts_flags &= ~TTS_FLAG_EMPTY;
-	if (shouldFree)
-		slot->tts_flags |= TTS_FLAG_SHOULDFREE;
-	slot->tts_tuple = tuple;
-	slot->tts_mintuple = NULL;
-
-	/* Mark extracted state invalid */
-	slot->tts_nvalid = 0;
-
-	/* Unpin any buffer pinned by the slot. */
-	if (BufferIsValid(slot->tts_buffer))
-		ReleaseBuffer(slot->tts_buffer);
-	slot->tts_buffer = InvalidBuffer;
+	if (!TTS_IS_HEAPTUPLE(slot))
+		elog(ERROR, "trying to store a heap tuple into wrong type of slot");
+	tts_heap_store_tuple(slot, tuple, shouldFree);
 
 	return slot;
 }
@@ -397,46 +1386,9 @@ ExecStoreBufferHeapTuple(HeapTuple tuple,
 	Assert(slot->tts_tupleDescriptor != NULL);
 	Assert(BufferIsValid(buffer));
 
-	/*
-	 * Free any old physical tuple belonging to the slot.
-	 */
-	if (TTS_SHOULDFREE(slot))
-	{
-		heap_freetuple(slot->tts_tuple);
-		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
-	}
-	if (TTS_SHOULDFREEMIN(slot))
-	{
-		heap_free_minimal_tuple(slot->tts_mintuple);
-		slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
-	}
-
-	/*
-	 * Store the new tuple into the specified slot.
-	 */
-	slot->tts_flags &= ~TTS_FLAG_EMPTY;
-	slot->tts_tuple = tuple;
-	slot->tts_mintuple = NULL;
-
-	/* Mark extracted state invalid */
-	slot->tts_nvalid = 0;
-
-	/*
-	 * Keep the disk page containing the given tuple pinned as long as we hold
-	 * a pointer into it.  We assume the caller already has such a pin.
-	 *
-	 * This is coded to optimize the case where the slot previously held a
-	 * tuple on the same disk page: in that case releasing and re-acquiring the
-	 * pin is a waste of cycles.  This is a common situation during seqscans,
-	 * so it's worth troubling over.
-	 */
-	if (slot->tts_buffer != buffer)
-	{
-		if (BufferIsValid(slot->tts_buffer))
-			ReleaseBuffer(slot->tts_buffer);
-		slot->tts_buffer = buffer;
-		IncrBufferRefCount(buffer);
-	}
+	if (!TTS_IS_BUFFERTUPLE(slot))
+		elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
+	tts_buffer_heap_store_tuple(slot, tuple, buffer);
 
 	return slot;
 }
@@ -461,93 +1413,9 @@ ExecStoreMinimalTuple(MinimalTuple mtup,
 	Assert(slot != NULL);
 	Assert(slot->tts_tupleDescriptor != NULL);
 
-	/*
-	 * Free any old physical tuple belonging to the slot.
-	 */
-	if (TTS_SHOULDFREE(slot))
-	{
-		heap_freetuple(slot->tts_tuple);
-		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
-	}
-	if (TTS_SHOULDFREEMIN(slot))
-	{
-		heap_free_minimal_tuple(slot->tts_mintuple);
-		slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
-	}
-
-	/*
-	 * Drop the pin on the referenced buffer, if there is one.
-	 */
-	if (BufferIsValid(slot->tts_buffer))
-		ReleaseBuffer(slot->tts_buffer);
-
-	slot->tts_buffer = InvalidBuffer;
-
-	/*
-	 * Store the new tuple into the specified slot.
-	 */
-	slot->tts_flags &= ~TTS_FLAG_EMPTY;
-	if (shouldFree)
-		slot->tts_flags |= TTS_FLAG_SHOULDFREEMIN;
-	slot->tts_tuple = &slot->tts_minhdr;
-	slot->tts_mintuple = mtup;
-
-	slot->tts_minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
-	slot->tts_minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
-	/* no need to set t_self or t_tableOid since we won't allow access */
-
-	/* Mark extracted state invalid */
-	slot->tts_nvalid = 0;
-
-	return slot;
-}
-
-/* --------------------------------
- *		ExecClearTuple
- *
- *		This function is used to clear out a slot in the tuple table.
- *
- *		NB: only the tuple is cleared, not the tuple descriptor (if any).
- * --------------------------------
- */
-TupleTableSlot *				/* return: slot passed */
-ExecClearTuple(TupleTableSlot *slot)	/* slot in which to store tuple */
-{
-	/*
-	 * sanity checks
-	 */
-	Assert(slot != NULL);
-
-	/*
-	 * Free the old physical tuple if necessary.
-	 */
-	if (TTS_SHOULDFREE(slot))
-	{
-		heap_freetuple(slot->tts_tuple);
-		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
-	}
-	if (TTS_SHOULDFREEMIN(slot))
-	{
-		heap_free_minimal_tuple(slot->tts_mintuple);
-		slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
-	}
-
-	slot->tts_tuple = NULL;
-	slot->tts_mintuple = NULL;
-
-	/*
-	 * Drop the pin on the referenced buffer, if there is one.
-	 */
-	if (BufferIsValid(slot->tts_buffer))
-		ReleaseBuffer(slot->tts_buffer);
-
-	slot->tts_buffer = InvalidBuffer;
-
-	/*
-	 * Mark it empty.
-	 */
-	slot->tts_flags |= TTS_FLAG_EMPTY;
-	slot->tts_nvalid = 0;
+	if (!TTS_IS_MINIMALTUPLE(slot))
+		elog(ERROR, "trying to store a minimal tuple into wrong type of slot");
+	tts_minimal_store_tuple(slot, mtup, shouldFree);
 
 	return slot;
 }
@@ -611,79 +1479,19 @@ ExecStoreAllNullTuple(TupleTableSlot *slot)
 }
 
 /* --------------------------------
- *		ExecCopySlotTuple
- *			Obtain a copy of a slot's regular physical tuple.  The copy is
- *			palloc'd in the current memory context.
- *			The slot itself is undisturbed.
+ *		ExecFetchSlotTuple
+ *			Fetch the slot's regular physical tuple.
  *
- *		This works even if the slot contains a virtual or minimal tuple;
- *		however the "system columns" of the result will not be meaningful.
+ *		This is a thin wrapper around TupleTableSlotType specific
+ *		get_heap_tuple callback. The callback is expected to return a heap
+ *		tuple as is if it holds one and continue to have ownership of the heap
+ *		tuple. If materialize is true, the function calls TupleTableSlotType
+ *		specific materialize() callback which is expected to materialize the
+ *		tuple within the slot so that the slot "owns" it. If materialize is
+ *		false, the returned tuple is not guaranteed to have storage local to
+ *		the slot and hence should be treated as read-only.
  * --------------------------------
  */
-HeapTuple
-ExecCopySlotTuple(TupleTableSlot *slot)
-{
-	/*
-	 * sanity checks
-	 */
-	Assert(slot != NULL);
-	Assert(!TTS_EMPTY(slot));
-
-	/*
-	 * If we have a physical tuple (either format) then just copy it.
-	 */
-	if (TTS_HAS_PHYSICAL_TUPLE(slot))
-		return heap_copytuple(slot->tts_tuple);
-	if (slot->tts_mintuple)
-		return heap_tuple_from_minimal_tuple(slot->tts_mintuple);
-
-	/*
-	 * Otherwise we need to build a tuple from the Datum array.
-	 */
-	return heap_form_tuple(slot->tts_tupleDescriptor,
-						   slot->tts_values,
-						   slot->tts_isnull);
-}
-
-/* --------------------------------
- *		ExecCopySlotMinimalTuple
- *			Obtain a copy of a slot's minimal physical tuple.  The copy is
- *			palloc'd in the current memory context.
- *			The slot itself is undisturbed.
- * --------------------------------
- */
-MinimalTuple
-ExecCopySlotMinimalTuple(TupleTableSlot *slot)
-{
-	/*
-	 * sanity checks
-	 */
-	Assert(slot != NULL);
-	Assert(!TTS_EMPTY(slot));
-
-	/*
-	 * If we have a physical tuple then just copy it.  Prefer to copy
-	 * tts_mintuple since that's a tad cheaper.
-	 */
-	if (slot->tts_mintuple)
-		return heap_copy_minimal_tuple(slot->tts_mintuple);
-	if (slot->tts_tuple)
-	{
-		if (HeapTupleHeaderGetNatts(slot->tts_tuple->t_data)
-			< slot->tts_tupleDescriptor->natts)
-			return minimal_expand_tuple(slot->tts_tuple,
-										slot->tts_tupleDescriptor);
-		else
-			return minimal_tuple_from_heap_tuple(slot->tts_tuple);
-	}
-
-	/*
-	 * Otherwise we need to build a tuple from the Datum array.
-	 */
-	return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
-								   slot->tts_values,
-								   slot->tts_isnull);
-}
 
 /*
  * ExecFetchSlotHeapTuple - fetch HeapTuple representing the slot's content
@@ -713,89 +1521,67 @@ ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
 	Assert(slot != NULL);
 	Assert(!TTS_EMPTY(slot));
 
-	if (shouldFree)
-		*shouldFree = false;
+	/* Materialize the tuple so that the slot "owns" it, if requested. */
+	if (materialize)
+		slot->tts_cb->materialize(slot);
 
-	/*
-	 * If we have a regular physical tuple then just return it.
-	 */
-	if (TTS_HAS_PHYSICAL_TUPLE(slot))
+	if (slot->tts_cb->get_heap_tuple == NULL)
 	{
-		if (HeapTupleHeaderGetNatts(slot->tts_tuple->t_data) <
-			slot->tts_tupleDescriptor->natts)
-		{
-			HeapTuple	tuple;
-			MemoryContext oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
-
-			tuple = heap_expand_tuple(slot->tts_tuple,
-									  slot->tts_tupleDescriptor);
-			MemoryContextSwitchTo(oldContext);
-			slot = ExecStoreHeapTuple(tuple, slot, true);
-		}
-		return slot->tts_tuple;
+		if (shouldFree)
+			*shouldFree = true;
+		return slot->tts_cb->copy_heap_tuple(slot);
+	}
+	else
+	{
+		if (shouldFree)
+			*shouldFree = false;
+		return slot->tts_cb->get_heap_tuple(slot);
 	}
-
-	/*
-	 * Otherwise materialize the slot...
-	 */
-	ExecMaterializeSlot(slot);
-
-	return slot->tts_tuple;
 }
 
 /* --------------------------------
  *		ExecFetchSlotMinimalTuple
  *			Fetch the slot's minimal physical tuple.
  *
- *		If the slot contains a virtual tuple, we convert it to minimal
- *		physical form.  The slot retains ownership of the minimal tuple.
- *		If it contains a regular tuple we convert to minimal form and store
- *		that in addition to the regular tuple (not instead of, because
- *		callers may hold pointers to Datums within the regular tuple).
+ *		If the given tuple table slot can hold a minimal tuple, indicated by a
+ *		non-NULL get_minimal_tuple callback, the function returns the minimal
+ *		tuple returned by that callback. It assumes that the minimal tuple
+ *		returned by the callback is "owned" by the slot i.e. the slot is
+ *		responsible for freeing the memory consumed by the tuple. Hence it sets
+ *		*shouldFree to false, indicating that the caller should not free the
+ *		memory consumed by the minimal tuple. In this case the returned minimal
+ *		tuple should be considered as read-only.
  *
- * As above, the result must be treated as read-only.
+ *		If that callback is not supported, it calls copy_minimal_tuple callback
+ *		which is expected to return a copy of minimal tuple represnting the
+ *		contents of the slot. In this case *shouldFree is set to true,
+ *		indicating the caller that it should free the memory consumed by the
+ *		minimal tuple. In this case the returned minimal tuple may be written
+ *		up.
  * --------------------------------
  */
 MinimalTuple
-ExecFetchSlotMinimalTuple(TupleTableSlot *slot, bool *shouldFree)
+ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
+						  bool *shouldFree)
 {
-	MemoryContext oldContext;
-
 	/*
 	 * sanity checks
 	 */
 	Assert(slot != NULL);
 	Assert(!TTS_EMPTY(slot));
 
-	if (shouldFree)
-		*shouldFree = false;
-
-	/*
-	 * If we have a minimal physical tuple (local or not) then just return it.
-	 */
-	if (slot->tts_mintuple)
-		return slot->tts_mintuple;
-
-	/*
-	 * Otherwise, copy or build a minimal tuple, and store it into the slot.
-	 *
-	 * We may be called in a context that is shorter-lived than the tuple
-	 * slot, but we have to ensure that the materialized tuple will survive
-	 * anyway.
-	 */
-	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
-	slot->tts_mintuple = ExecCopySlotMinimalTuple(slot);
-	slot->tts_flags |= TTS_FLAG_SHOULDFREEMIN;
-	MemoryContextSwitchTo(oldContext);
-
-	/*
-	 * Note: we may now have a situation where we have a local minimal tuple
-	 * attached to a virtual or non-local physical tuple.  There seems no harm
-	 * in that at the moment, but if any materializes, we should change this
-	 * function to force the slot into minimal-tuple-only state.
-	 */
-
-	return slot->tts_mintuple;
+	if (slot->tts_cb->get_minimal_tuple)
+	{
+		if (shouldFree)
+			*shouldFree = false;
+		return slot->tts_cb->get_minimal_tuple(slot);
+	}
+	else
+	{
+		if (shouldFree)
+			*shouldFree = true;
+		return slot->tts_cb->copy_minimal_tuple(slot);
+	}
 }
 
 /* --------------------------------
@@ -826,103 +1612,58 @@ ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
 	return ret;
 }
 
-/* ExecMaterializeSlot - force a slot into the "materialized" state.
- *
- * This causes the slot's tuple to be a local copy not dependent on any
- * external storage (i.e. pointing into a Buffer, or having allocations in
- * another memory context).
- *
- * A typical use for this operation is to prepare a computed tuple for being
- * stored on disk.  The original data may or may not be virtual, but in any
- * case we need a private copy for heap_insert to scribble on.
- */
 void
-ExecMaterializeSlot(TupleTableSlot *slot)
+ExecForceStoreHeapTuple(HeapTuple tuple,
+						TupleTableSlot *slot)
 {
-	MemoryContext oldContext;
+	if (TTS_IS_HEAPTUPLE(slot))
+	{
+		ExecStoreHeapTuple(tuple, slot, false);
+	}
+	else if (TTS_IS_BUFFERTUPLE(slot))
+	{
+		MemoryContext oldContext;
+		BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
 
-	/*
-	 * sanity checks
-	 */
-	Assert(slot != NULL);
-	Assert(!TTS_EMPTY(slot));
-
-	/*
-	 * If we have a regular physical tuple, and it's locally palloc'd, we have
-	 * nothing to do.
-	 */
-	if (slot->tts_tuple && TTS_SHOULDFREE(slot))
-		return;
-
-	/*
-	 * Otherwise, copy or build a physical tuple, and store it into the slot.
-	 *
-	 * We may be called in a context that is shorter-lived than the tuple
-	 * slot, but we have to ensure that the materialized tuple will survive
-	 * anyway.
-	 */
-	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
-	slot->tts_tuple = ExecCopySlotTuple(slot);
-	slot->tts_flags |= TTS_FLAG_SHOULDFREE;
-	MemoryContextSwitchTo(oldContext);
-
-	/*
-	 * Drop the pin on the referenced buffer, if there is one.
-	 */
-	if (BufferIsValid(slot->tts_buffer))
-		ReleaseBuffer(slot->tts_buffer);
-
-	slot->tts_buffer = InvalidBuffer;
-
-	/*
-	 * Mark extracted state invalid.  This is important because the slot is
-	 * not supposed to depend any more on the previous external data; we
-	 * mustn't leave any dangling pass-by-reference datums in tts_values.
-	 * However, we have not actually invalidated any such datums, if there
-	 * happen to be any previously fetched from the slot.  (Note in particular
-	 * that we have not pfree'd tts_mintuple, if there is one.)
-	 */
-	slot->tts_nvalid = 0;
-
-	/*
-	 * On the same principle of not depending on previous remote storage,
-	 * forget the mintuple if it's not local storage.  (If it is local
-	 * storage, we must not pfree it now, since callers might have already
-	 * fetched datum pointers referencing it.)
-	 */
-	if (!TTS_SHOULDFREEMIN(slot))
-		slot->tts_mintuple = NULL;
+		ExecClearTuple(slot);
+		slot->tts_flags |= TTS_FLAG_SHOULDFREE;
+		slot->tts_flags &= ~TTS_FLAG_EMPTY;
+		oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
+		bslot->base.tuple = heap_copytuple(tuple);
+		MemoryContextSwitchTo(oldContext);
+	}
+	else
+	{
+		ExecClearTuple(slot);
+		heap_deform_tuple(tuple, slot->tts_tupleDescriptor,
+						  slot->tts_values, slot->tts_isnull);
+		ExecStoreVirtualTuple(slot);
+	}
 }
 
-/* --------------------------------
- *		ExecCopySlot
- *			Copy the source slot's contents into the destination slot.
- *
- *		The destination acquires a private copy that will not go away
- *		if the source is cleared.
- *
- *		The caller must ensure the slots have compatible tupdescs.
- * --------------------------------
- */
-TupleTableSlot *
-ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
+void
+ExecForceStoreMinimalTuple(MinimalTuple mtup,
+						   TupleTableSlot *slot,
+						   bool shouldFree)
 {
-	HeapTuple	newTuple;
-	MemoryContext oldContext;
+	if (TTS_IS_MINIMALTUPLE(slot))
+	{
+		tts_minimal_store_tuple(slot, mtup, shouldFree);
+	}
+	else
+	{
+		HeapTupleData htup;
 
-	/*
-	 * There might be ways to optimize this when the source is virtual, but
-	 * for now just always build a physical copy.  Make sure it is in the
-	 * right context.
-	 */
-	oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
-	newTuple = ExecCopySlotTuple(srcslot);
-	MemoryContextSwitchTo(oldContext);
+		ExecClearTuple(slot);
 
-	return ExecStoreHeapTuple(newTuple, dstslot, true);
+		htup.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
+		htup.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
+		heap_deform_tuple(&htup, slot->tts_tupleDescriptor,
+						  slot->tts_values, slot->tts_isnull);
+		ExecStoreVirtualTuple(slot);
+	}
 }
 
-
 /* ----------------------------------------------------------------
  *				convenience initialization routines
  * ----------------------------------------------------------------
@@ -1062,7 +1803,6 @@ void
 slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
 {
 	AttrMissing *attrmiss = NULL;
-	int			missattnum;
 
 	if (slot->tts_tupleDescriptor->constr)
 		attrmiss = slot->tts_tupleDescriptor->constr->missing;
@@ -1077,6 +1817,8 @@ slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
 	}
 	else
 	{
+		int			missattnum;
+
 		/* if there is a missing values array we must process them one by one */
 		for (missattnum = startAttNum;
 			 missattnum < lastAttNum;
@@ -1085,143 +1827,36 @@ slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
 			slot->tts_values[missattnum] = attrmiss[missattnum].am_value;
 			slot->tts_isnull[missattnum] = !attrmiss[missattnum].am_present;
 		}
+
 	}
 }
 
 /*
- * slot_getattr
- *		This function fetches an attribute of the slot's current tuple.
- *		It is functionally equivalent to heap_getattr, but fetches of
- *		multiple attributes of the same tuple will be optimized better,
- *		because we avoid O(N^2) behavior from multiple calls of
- *		nocachegetattr(), even when attcacheoff isn't usable.
+ * slot_getsomeattrs_int
  *
- *		A difference from raw heap_getattr is that attnums beyond the
- *		slot's tupdesc's last attribute will be considered NULL even
- *		when the physical tuple is longer than the tupdesc.
- */
-Datum
-slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
-{
-	HeapTuple	tuple = slot->tts_tuple;
-	TupleDesc	tupleDesc = slot->tts_tupleDescriptor;
-	HeapTupleHeader tup;
-
-	/*
-	 * system attributes are handled by heap_getsysattr
-	 */
-	if (attnum <= 0)
-	{
-		if (tuple == NULL)		/* internal error */
-			elog(ERROR, "cannot extract system attribute from virtual tuple");
-		if (tuple == &(slot->tts_minhdr))	/* internal error */
-			elog(ERROR, "cannot extract system attribute from minimal tuple");
-		return heap_getsysattr(tuple, attnum, tupleDesc, isnull);
-	}
-
-	/*
-	 * fast path if desired attribute already cached
-	 */
-	if (attnum <= slot->tts_nvalid)
-	{
-		*isnull = slot->tts_isnull[attnum - 1];
-		return slot->tts_values[attnum - 1];
-	}
-
-	/*
-	 * return NULL if attnum is out of range according to the tupdesc
-	 */
-	if (attnum > tupleDesc->natts)
-	{
-		*isnull = true;
-		return (Datum) 0;
-	}
-
-	/*
-	 * otherwise we had better have a physical tuple (tts_nvalid should equal
-	 * natts in all virtual-tuple cases)
-	 */
-	if (tuple == NULL)			/* internal error */
-		elog(ERROR, "cannot extract attribute from empty tuple slot");
-
-	/*
-	 * return NULL or missing value if attnum is out of range according to the
-	 * tuple
-	 *
-	 * (We have to check this separately because of various inheritance and
-	 * table-alteration scenarios: the tuple could be either longer or shorter
-	 * than the tupdesc.)
-	 */
-	tup = tuple->t_data;
-	if (attnum > HeapTupleHeaderGetNatts(tup))
-		return getmissingattr(slot->tts_tupleDescriptor, attnum, isnull);
-
-	/*
-	 * check if target attribute is null: no point in groveling through tuple
-	 */
-	if (HeapTupleHasNulls(tuple) && att_isnull(attnum - 1, tup->t_bits))
-	{
-		*isnull = true;
-		return (Datum) 0;
-	}
-
-	/*
-	 * Extract the attribute, along with any preceding attributes.
-	 */
-	slot_deform_tuple(slot, attnum);
-
-	/*
-	 * The result is acquired from tts_values array.
-	 */
-	*isnull = slot->tts_isnull[attnum - 1];
-	return slot->tts_values[attnum - 1];
-}
-
-/*
- * slot_getsomeattrs
- *		This function forces the entries of the slot's Datum/isnull
- *		arrays to be valid at least up through the attnum'th entry.
  */
 void
-slot_getsomeattrs(TupleTableSlot *slot, int attnum)
+slot_getsomeattrs_int(TupleTableSlot *slot, int attnum)
 {
-	HeapTuple	tuple;
-	int			attno;
+	/* Check for caller errors */
+	Assert(slot->tts_nvalid < attnum); /* slot_getsomeattr checked */
+	Assert(attnum > 0);
 
-	/* Quick out if we have 'em all already */
-	if (slot->tts_nvalid >= attnum)
-		return;
-
-	/* Check for caller error */
-	if (attnum <= 0 || attnum > slot->tts_tupleDescriptor->natts)
+	if (unlikely(attnum > slot->tts_tupleDescriptor->natts))
 		elog(ERROR, "invalid attribute number %d", attnum);
 
-	/*
-	 * otherwise we had better have a physical tuple (tts_nvalid should equal
-	 * natts in all virtual-tuple cases)
-	 */
-	tuple = slot->tts_tuple;
-	if (tuple == NULL)			/* internal error */
-		elog(ERROR, "cannot extract attribute from empty tuple slot");
+	/* Fetch as many attributes as possible from the underlying tuple. */
+	slot->tts_cb->getsomeattrs(slot, attnum);
 
 	/*
-	 * load up any slots available from physical tuple
+	 * If the underlying tuple doesn't have enough attributes, tuple descriptor
+	 * must have the missing attributes.
 	 */
-	attno = HeapTupleHeaderGetNatts(tuple->t_data);
-	attno = Min(attno, attnum);
-
-	slot_deform_tuple(slot, attno);
-
-	attno = slot->tts_nvalid;
-
-	/*
-	 * If tuple doesn't have all the atts indicated by attnum, read the rest
-	 * as NULLs or missing values
-	 */
-	if (attno < attnum)
-		slot_getmissingattrs(slot, attno, attnum);
-
-	slot->tts_nvalid = attnum;
+	if (unlikely(slot->tts_nvalid < attnum))
+	{
+		slot_getmissingattrs(slot, slot->tts_nvalid, attnum);
+		slot->tts_nvalid = attnum;
+	}
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 20d6d8e9cbb..2a1a6123d3b 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1800,9 +1800,8 @@ agg_retrieve_direct(AggState *aggstate)
 				 * reserved for it.  The tuple will be deleted when it is
 				 * cleared from the slot.
 				 */
-				ExecStoreHeapTuple(aggstate->grp_firstTuple,
-								   firstSlot,
-								   true);
+				ExecForceStoreHeapTuple(aggstate->grp_firstTuple,
+								   firstSlot);
 				aggstate->grp_firstTuple = NULL;	/* don't keep two pointers */
 
 				/* set up for first advance_aggregates call */
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index d9afd0bdded..8fb477f45c3 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -929,9 +929,10 @@ ExecParallelHashJoinOuterGetTuple(PlanState *outerNode,
 									   hashvalue);
 		if (tuple != NULL)
 		{
-			slot = ExecStoreMinimalTuple(tuple,
-										 hjstate->hj_OuterTupleSlot,
-										 false);
+			ExecForceStoreMinimalTuple(tuple,
+									   hjstate->hj_OuterTupleSlot,
+									   false);
+			slot = hjstate->hj_OuterTupleSlot;
 			return slot;
 		}
 		else
@@ -1158,9 +1159,10 @@ ExecParallelHashJoinNewBatch(HashJoinState *hjstate)
 					while ((tuple = sts_parallel_scan_next(inner_tuples,
 														   &hashvalue)))
 					{
-						slot = ExecStoreMinimalTuple(tuple,
-													 hjstate->hj_HashTupleSlot,
-													 false);
+						ExecForceStoreMinimalTuple(tuple,
+												   hjstate->hj_HashTupleSlot,
+												   false);
+						slot = hjstate->hj_HashTupleSlot;
 						ExecParallelHashTableInsertCurrentBatch(hashtable, slot,
 																hashvalue);
 					}
@@ -1294,7 +1296,8 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not read from hash-join temporary file: %m")));
-	return ExecStoreMinimalTuple(tuple, tupleSlot, true);
+	ExecForceStoreMinimalTuple(tuple, tupleSlot, true);
+	return tupleSlot;
 }
 
 
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 9cc499d6533..d29162bab79 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2059,6 +2059,15 @@ ExecModifyTable(PlanState *pstate)
 				break;
 		}
 
+		/*
+		 * Ensure input tuple is the right format for the target relation.
+		 */
+		if (node->mt_scans[node->mt_whichplan]->tts_cb != planSlot->tts_cb)
+		{
+			ExecCopySlot(node->mt_scans[node->mt_whichplan], planSlot);
+			planSlot = node->mt_scans[node->mt_whichplan];
+		}
+
 		/*
 		 * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
 		 * here is compute the RETURNING expressions.
@@ -2242,6 +2251,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 
 	mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
 	mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
+	mtstate->mt_scans = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
 
 	/* If modifying a partitioned table, initialize the root table info */
 	if (node->rootResultRelIndex >= 0)
@@ -2308,6 +2318,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 		/* Now init the plan for this result rel */
 		estate->es_result_relation_info = resultRelInfo;
 		mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
+		mtstate->mt_scans[i] =
+			ExecInitExtraTupleSlot(mtstate->ps.state, ExecGetResultType(mtstate->mt_plans[i]),
+								   &TTSOpsHeapTuple);
 
 		/* Also let FDWs init themselves for foreign-table result rels */
 		if (!resultRelInfo->ri_usesFdwDirectModify &&
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 62811ed0302..b42e60576e3 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -988,6 +988,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
 		 * across-type comparison).
 		 */
 		sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
+													 &TTSOpsVirtual, &TTSOpsMinimalTuple,
 													 ncols,
 													 sstate->keyColIdx,
 													 sstate->tab_eq_funcoids,
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index 168072afd2f..162d1be89bd 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -65,6 +65,8 @@ LLVMTypeRef StructFormPgAttribute;
 LLVMTypeRef StructTupleConstr;
 LLVMTypeRef StructtupleDesc;
 LLVMTypeRef StructTupleTableSlot;
+LLVMTypeRef StructHeapTupleTableSlot;
+LLVMTypeRef StructMinimalTupleTableSlot;
 LLVMTypeRef StructMemoryContextData;
 LLVMTypeRef StructPGFinfoRecord;
 LLVMTypeRef StructFmgrInfo;
@@ -79,7 +81,7 @@ LLVMTypeRef StructAggStatePerTransData;
 LLVMValueRef AttributeTemplate;
 LLVMValueRef FuncStrlen;
 LLVMValueRef FuncVarsizeAny;
-LLVMValueRef FuncSlotGetsomeattrs;
+LLVMValueRef FuncSlotGetsomeattrsInt;
 LLVMValueRef FuncSlotGetmissingattrs;
 LLVMValueRef FuncMakeExpandedObjectReadOnlyInternal;
 LLVMValueRef FuncExecEvalArrayRefSubscript;
@@ -811,6 +813,8 @@ llvm_create_types(void)
 	StructFunctionCallInfoData = load_type(mod, "StructFunctionCallInfoData");
 	StructMemoryContextData = load_type(mod, "StructMemoryContextData");
 	StructTupleTableSlot = load_type(mod, "StructTupleTableSlot");
+	StructHeapTupleTableSlot = load_type(mod, "StructHeapTupleTableSlot");
+	StructMinimalTupleTableSlot = load_type(mod, "StructMinimalTupleTableSlot");
 	StructHeapTupleData = load_type(mod, "StructHeapTupleData");
 	StructtupleDesc = load_type(mod, "StructtupleDesc");
 	StructAggState = load_type(mod, "StructAggState");
@@ -820,7 +824,7 @@ llvm_create_types(void)
 	AttributeTemplate = LLVMGetNamedFunction(mod, "AttributeTemplate");
 	FuncStrlen = LLVMGetNamedFunction(mod, "strlen");
 	FuncVarsizeAny = LLVMGetNamedFunction(mod, "varsize_any");
-	FuncSlotGetsomeattrs = LLVMGetNamedFunction(mod, "slot_getsomeattrs");
+	FuncSlotGetsomeattrsInt = LLVMGetNamedFunction(mod, "slot_getsomeattrs_int");
 	FuncSlotGetmissingattrs = LLVMGetNamedFunction(mod, "slot_getmissingattrs");
 	FuncMakeExpandedObjectReadOnlyInternal = LLVMGetNamedFunction(mod, "MakeExpandedObjectReadOnlyInternal");
 	FuncExecEvalArrayRefSubscript = LLVMGetNamedFunction(mod, "ExecEvalArrayRefSubscript");
diff --git a/src/backend/jit/llvm/llvmjit_deform.c b/src/backend/jit/llvm/llvmjit_deform.c
index 59e38d2d955..e430cd9eda4 100644
--- a/src/backend/jit/llvm/llvmjit_deform.c
+++ b/src/backend/jit/llvm/llvmjit_deform.c
@@ -31,7 +31,7 @@
  * Create a function that deforms a tuple of type desc up to natts columns.
  */
 LLVMValueRef
-slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts)
+slot_compile_deform(LLVMJitContext *context, TupleDesc desc, const TupleTableSlotOps *ops, int natts)
 {
 	char	   *funcname;
 
@@ -88,6 +88,16 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts)
 
 	int			attnum;
 
+	if (ops != &TTSOpsHeapTuple && ops != &TTSOpsBufferTuple &&
+		ops != &TTSOpsMinimalTuple)
+	{
+		/*
+		 * Decline to JIT for slot types we don't know to handle, or don't
+		 * want to handle (say virtual slots).
+		 */
+		return NULL;
+	}
+
 	mod = llvm_mutable_module(context);
 
 	funcname = llvm_expand_funcname(context, "deform");
@@ -166,14 +176,44 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts)
 	v_tts_nulls =
 		l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_ISNULL,
 						  "tts_ISNULL");
-
-	v_slotoffp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_OFF, "");
 	v_flagsp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_FLAGS, "");
 	v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, "");
 
-	v_tupleheaderp =
-		l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_TUPLE,
-						  "tupleheader");
+	if (ops == &TTSOpsHeapTuple || ops == &TTSOpsBufferTuple)
+	{
+		LLVMValueRef v_heapslot;
+
+		v_heapslot =
+			LLVMBuildBitCast(b,
+							 v_slot,
+							 l_ptr(StructHeapTupleTableSlot),
+							 "heapslot");
+		v_slotoffp = LLVMBuildStructGEP(b, v_heapslot, FIELDNO_HEAPTUPLETABLESLOT_OFF, "");
+		v_tupleheaderp =
+			l_load_struct_gep(b, v_heapslot, FIELDNO_HEAPTUPLETABLESLOT_TUPLE,
+							  "tupleheader");
+
+	}
+	else if (ops == &TTSOpsMinimalTuple)
+	{
+		LLVMValueRef v_minimalslot;
+
+		v_minimalslot =
+			LLVMBuildBitCast(b,
+							 v_slot,
+							 l_ptr(StructMinimalTupleTableSlot),
+							 "minimalslotslot");
+		v_slotoffp = LLVMBuildStructGEP(b, v_minimalslot, FIELDNO_MINIMALTUPLETABLESLOT_OFF, "");
+		v_tupleheaderp =
+			l_load_struct_gep(b, v_minimalslot, FIELDNO_MINIMALTUPLETABLESLOT_TUPLE,
+							  "tupleheader");
+	}
+	else
+	{
+		/* should've returned at the start of the function */
+		pg_unreachable();
+	}
+
 	v_tuplep =
 		l_load_struct_gep(b, v_tupleheaderp, FIELDNO_HEAPTUPLEDATA_DATA,
 						  "tuple");
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 63b921517c6..f3414ef9caf 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -324,6 +324,7 @@ llvm_compile_expr(ExprState *state)
 					{
 						l_jit_deform =
 							slot_compile_deform(context, desc,
+												tts_cb,
 												op->d.fetch.last_var);
 					}
 
@@ -344,7 +345,7 @@ llvm_compile_expr(ExprState *state)
 						params[1] = l_int32_const(op->d.fetch.last_var);
 
 						LLVMBuildCall(b,
-									  llvm_get_decl(mod, FuncSlotGetsomeattrs),
+									  llvm_get_decl(mod, FuncSlotGetsomeattrsInt),
 									  params, lengthof(params), "");
 					}
 
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 855a6977ee5..2df1882b750 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -59,6 +59,8 @@ FunctionCallInfoData StructFunctionCallInfoData;
 HeapTupleData StructHeapTupleData;
 MemoryContextData StructMemoryContextData;
 TupleTableSlot StructTupleTableSlot;
+HeapTupleTableSlot StructHeapTupleTableSlot;
+MinimalTupleTableSlot StructMinimalTupleTableSlot;
 struct tupleDesc StructtupleDesc;
 
 
@@ -97,7 +99,7 @@ void	   *referenced_functions[] =
 {
 	strlen,
 	varsize_any,
-	slot_getsomeattrs,
+	slot_getsomeattrs_int,
 	slot_getmissingattrs,
 	MakeExpandedObjectReadOnlyInternal,
 	ExecEvalArrayRefSubscript,
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 97d240fdbb0..1867a70f6f3 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -835,7 +835,5 @@ extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup);
 extern size_t varsize_any(void *p);
 extern HeapTuple heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc);
 extern MinimalTuple minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc);
-struct TupleTableSlot;
-extern void slot_deform_tuple(struct TupleTableSlot *slot, int natts);
 
 #endif							/* HTUP_DETAILS_H */
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 4f156f4a5e7..8b48a23d13e 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -249,6 +249,7 @@ extern List *ExecInitExprList(List *nodes, PlanState *parent);
 extern ExprState *ExecBuildAggTrans(AggState *aggstate, struct AggStatePerPhaseData *phase,
 				  bool doSort, bool doHash);
 extern ExprState *ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc,
+					   const TupleTableSlotOps *lops, const TupleTableSlotOps *rops,
 					   int numCols,
 					   AttrNumber *keyColIdx,
 					   Oid *eqfunctions,
diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h
index a6f6084f0a9..f78853488a9 100644
--- a/src/include/executor/tuptable.h
+++ b/src/include/executor/tuptable.h
@@ -65,7 +65,7 @@
  * ie, only as needed.  This serves to avoid repeated extraction of data
  * from the physical tuple.
  *
- * A TupleTableSlot can also be "empty", indicated by flag TTS_EMPTY set in
+ * A TupleTableSlot can also be "empty", indicated by flag TTS_FLAG_EMPTY set in
  * tts_flags, holding no valid data.  This is the only valid state for a
  * freshly-created slot that has not yet had a tuple descriptor assigned to it.
  * In this state, TTS_SHOULDFREE should not be set in tts_flag, tts_tuple must
@@ -116,25 +116,22 @@
 #define			TTS_FLAG_EMPTY			(1 << 1)
 #define TTS_EMPTY(slot)	(((slot)->tts_flags & TTS_FLAG_EMPTY) != 0)
 
-/* should pfree tts_tuple? */
+/* should pfree tuple "owned" by the slot? */
 #define			TTS_FLAG_SHOULDFREE		(1 << 2)
 #define TTS_SHOULDFREE(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREE) != 0)
 
-/* should pfree tts_mintuple? */
-#define			TTS_FLAG_SHOULDFREEMIN	(1 << 3)
-#define TTS_SHOULDFREEMIN(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREEMIN) != 0)
-
 /* saved state for slot_deform_tuple */
-#define			TTS_FLAG_SLOW		(1 << 4)
+#define			TTS_FLAG_SLOW		(1 << 3)
 #define TTS_SLOW(slot) (((slot)->tts_flags & TTS_FLAG_SLOW) != 0)
 
 /* fixed tuple descriptor */
-#define			TTS_FLAG_FIXED		(1 << 5)
+#define			TTS_FLAG_FIXED		(1 << 4)
 #define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0)
 
 struct TupleTableSlotOps;
 typedef struct TupleTableSlotOps TupleTableSlotOps;
 
+/* virtual or base type */
 typedef struct TupleTableSlot
 {
 	NodeTag		type;
@@ -142,26 +139,98 @@ typedef struct TupleTableSlot
 	uint16		tts_flags;		/* Boolean states */
 #define FIELDNO_TUPLETABLESLOT_NVALID 2
 	AttrNumber	tts_nvalid;		/* # of valid values in tts_values */
-#define FIELDNO_TUPLETABLESLOT_TUPLE 3
-	HeapTuple	tts_tuple;		/* physical tuple, or NULL if virtual */
 	const TupleTableSlotOps *const tts_cb; /* implementation of slot */
-#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 5
+#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4
 	TupleDesc	tts_tupleDescriptor;	/* slot's tuple descriptor */
-	MemoryContext tts_mcxt;		/* slot itself is in this context */
-	Buffer		tts_buffer;		/* tuple's buffer, or InvalidBuffer */
-#define FIELDNO_TUPLETABLESLOT_OFF 8
-	uint32		tts_off;		/* saved state for slot_deform_tuple */
-#define FIELDNO_TUPLETABLESLOT_VALUES 9
+#define FIELDNO_TUPLETABLESLOT_VALUES 5
 	Datum	   *tts_values;		/* current per-attribute values */
-#define FIELDNO_TUPLETABLESLOT_ISNULL 10
+#define FIELDNO_TUPLETABLESLOT_ISNULL 6
 	bool	   *tts_isnull;		/* current per-attribute isnull flags */
-	MinimalTuple tts_mintuple;	/* minimal tuple, or NULL if none */
-	HeapTupleData tts_minhdr;	/* workspace for minimal-tuple-only case */
+	MemoryContext tts_mcxt;		/* slot itself is in this context */
 } TupleTableSlot;
 
 /* routines for a TupleTableSlot implementation */
 struct TupleTableSlotOps
 {
+	/* Minimum size of the slot */
+	size_t			base_slot_size;
+
+	/* Initialization. */
+	void (*init)(TupleTableSlot *slot);
+
+	/* Destruction. */
+	void (*release)(TupleTableSlot *slot);
+
+	/*
+	 * Clear the contents of the slot. Only the contents are expected to be
+	 * cleared and not the tuple descriptor. Typically an implementation of
+	 * this callback should free the memory allocated for the tuple contained
+	 * in the slot.
+	 */
+	void (*clear)(TupleTableSlot *slot);
+
+	/*
+	 * Fill up first natts entries of tts_values and tts_isnull arrays with
+	 * values from the tuple contained in the slot. The function may be called
+	 * with natts more than the number of attributes available in the tuple,
+	 * in which case it should set tts_nvalid to the number of returned
+	 * columns.
+	 */
+	void (*getsomeattrs)(TupleTableSlot *slot, int natts);
+
+	/*
+	 * Returns value of the given system attribute as a datum and sets isnull
+	 * to false, if it's not NULL. Throws an error if the slot type does not
+	 * support system attributes.
+	 */
+	Datum (*getsysattr)(TupleTableSlot *slot, int attnum, bool *isnull);
+
+	/*
+	 * Make the contents of the slot solely depend on the slot, and not on
+	 * underlying resources (like another memory context, buffers, etc).
+	 */
+	void (*materialize)(TupleTableSlot *slot);
+
+	/*
+	 * Copy the contents of the source slot into the destination slot's own
+	 * context. Invoked using callback of the destination slot.
+	 */
+	void (*copyslot) (TupleTableSlot *dstslot, TupleTableSlot *srcslot);
+
+	/*
+	 * Return a heap tuple "owned" by the slot. It is slot's responsibility to
+	 * free the memory consumed by the heap tuple. If the slot can not "own" a
+	 * heap tuple, it should not implement this callback and should set it as
+	 * NULL.
+	 */
+	HeapTuple (*get_heap_tuple)(TupleTableSlot *slot);
+
+	/*
+	 * Return a minimal tuple "owned" by the slot. It is slot's responsibility
+	 * to free the memory consumed by the minimal tuple. If the slot can not
+	 * "own" a minimal tuple, it should not implement this callback and should
+	 * set it as NULL.
+	 */
+	MinimalTuple (*get_minimal_tuple)(TupleTableSlot *slot);
+
+	/*
+	 * Return a copy of heap tuple representing the contents of the slot. The
+	 * returned heap tuple should be writable. The copy should be palloc'd in
+	 * the current memory context. The slot itself is expected to remain
+	 * undisturbed. It is *not* expected to have meaningful "system columns"
+	 * in the copy. The copy is not be "owned" by the slot i.e. the caller has
+	 * to take responsibilty to free memory consumed by the slot.
+	 */
+	HeapTuple (*copy_heap_tuple)(TupleTableSlot *slot);
+
+	/*
+	 * Return a copy of minimal tuple representing the contents of the slot.
+	 * The returned minimal tuple should be writable. The copy should be
+	 * palloc'd in the current memory context. The slot itself is expected to
+	 * remain undisturbed. The copy is not be "owned" by the slot i.e. the
+	 * caller has to take responsibilty to free memory consumed by the slot.
+	 */
+	MinimalTuple (*copy_minimal_tuple)(TupleTableSlot *slot);
 };
 
 /*
@@ -173,8 +242,44 @@ extern PGDLLIMPORT const TupleTableSlotOps TTSOpsHeapTuple;
 extern PGDLLIMPORT const TupleTableSlotOps TTSOpsMinimalTuple;
 extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferTuple;
 
-#define TTS_HAS_PHYSICAL_TUPLE(slot)  \
-	((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr))
+#define TTS_IS_VIRTUAL(slot) ((slot)->tts_cb == &TTSOpsVirtual)
+#define TTS_IS_HEAPTUPLE(slot) ((slot)->tts_cb == &TTSOpsHeapTuple)
+#define TTS_IS_MINIMALTUPLE(slot) ((slot)->tts_cb == &TTSOpsMinimalTuple)
+#define TTS_IS_BUFFERTUPLE(slot) ((slot)->tts_cb == &TTSOpsBufferTuple)
+
+
+typedef struct VirtualTupleTableSlot
+{
+	TupleTableSlot base;
+	char	   *data;		/* data for materialized slots */
+} VirtualTupleTableSlot;
+
+typedef struct HeapTupleTableSlot
+{
+	TupleTableSlot base;
+#define FIELDNO_HEAPTUPLETABLESLOT_TUPLE 1
+	HeapTuple	tuple;		/* physical tuple */
+#define FIELDNO_HEAPTUPLETABLESLOT_OFF 2
+	uint32		off;		/* saved state for slot_deform_tuple */
+} HeapTupleTableSlot;
+
+/* heap tuple residing in a buffer */
+typedef struct BufferHeapTupleTableSlot
+{
+	HeapTupleTableSlot base;
+	Buffer		buffer;		/* tuple's buffer, or InvalidBuffer */
+} BufferHeapTupleTableSlot;
+
+typedef struct MinimalTupleTableSlot
+{
+	TupleTableSlot base;
+#define FIELDNO_MINIMALTUPLETABLESLOT_TUPLE 1
+	HeapTuple	tuple;		/* tuple wrapper */
+	MinimalTuple mintuple;	/* minimal tuple, or NULL if none */
+	HeapTupleData minhdr;	/* workspace for minimal-tuple-only case */
+#define FIELDNO_MINIMALTUPLETABLESLOT_OFF 4
+	uint32		off;		/* saved state for slot_deform_tuple */
+} MinimalTupleTableSlot;
 
 /*
  * TupIsNull -- is a TupleTableSlot empty?
@@ -195,39 +300,38 @@ extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc);
 extern TupleTableSlot *ExecStoreHeapTuple(HeapTuple tuple,
 				   TupleTableSlot *slot,
 				   bool shouldFree);
+extern void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot);
 extern TupleTableSlot *ExecStoreBufferHeapTuple(HeapTuple tuple,
 						 TupleTableSlot *slot,
 						 Buffer buffer);
 extern TupleTableSlot *ExecStoreMinimalTuple(MinimalTuple mtup,
 					  TupleTableSlot *slot,
 					  bool shouldFree);
-extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot);
+extern void ExecForceStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot,
+									   bool shouldFree);
 extern TupleTableSlot *ExecStoreVirtualTuple(TupleTableSlot *slot);
 extern TupleTableSlot *ExecStoreAllNullTuple(TupleTableSlot *slot);
-extern HeapTuple ExecCopySlotTuple(TupleTableSlot *slot);
-extern MinimalTuple ExecCopySlotMinimalTuple(TupleTableSlot *slot);
-extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shoulFree);
+extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree);
 extern MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
 						  bool *shouldFree);
 extern Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot);
-extern void ExecMaterializeSlot(TupleTableSlot *slot);
-extern TupleTableSlot *ExecCopySlot(TupleTableSlot *dstslot,
-			 TupleTableSlot *srcslot);
 extern void slot_getmissingattrs(TupleTableSlot *slot, int startAttNum,
 					 int lastAttNum);
-extern Datum slot_getattr(TupleTableSlot *slot, int attnum,
-			 bool *isnull);
-extern void slot_getsomeattrs(TupleTableSlot *slot, int attnum);
-
-/* in access/common/heaptuple.c */
-extern bool slot_attisnull(TupleTableSlot *slot, int attnum);
-extern bool slot_getsysattr(TupleTableSlot *slot, int attnum,
-				Datum *value, bool *isnull);
-extern Datum getmissingattr(TupleDesc tupleDesc,
-			   int attnum, bool *isnull);
+extern void slot_getsomeattrs_int(TupleTableSlot *slot, int attnum);
 
 #ifndef FRONTEND
 
+/*
+ * This function forces the entries of the slot's Datum/isnull arrays to be
+ * valid at least up through the attnum'th entry.
+ */
+static inline void
+slot_getsomeattrs(TupleTableSlot *slot, int attnum)
+{
+	if (slot->tts_nvalid < attnum)
+		slot_getsomeattrs_int(slot, attnum);
+}
+
 /*
  * slot_getallattrs
  *		This function forces all the entries of the slot's Datum/isnull
@@ -240,6 +344,129 @@ slot_getallattrs(TupleTableSlot *slot)
 	slot_getsomeattrs(slot, slot->tts_tupleDescriptor->natts);
 }
 
-#endif
+
+/*
+ * slot_attisnull
+ *
+ * Detect whether an attribute of the slot is null, without actually fetching
+ * it.
+ */
+static inline bool
+slot_attisnull(TupleTableSlot *slot, int attnum)
+{
+	AssertArg(attnum > 0);
+
+	if (attnum > slot->tts_nvalid)
+		slot_getsomeattrs(slot, attnum);
+
+	return slot->tts_isnull[attnum - 1];
+}
+
+static inline Datum
+slot_getattr(TupleTableSlot *slot, int attnum,
+			 bool *isnull)
+{
+	AssertArg(attnum > 0);
+
+	if (attnum > slot->tts_nvalid)
+		slot_getsomeattrs(slot, attnum);
+
+	*isnull = slot->tts_isnull[attnum - 1];
+
+	return slot->tts_values[attnum - 1];
+}
+
+/*
+ * slot_getsysattr
+ *		This function fetches a system attribute of the slot's current tuple.
+ *		If the slot type does not contain system attributes, this will throw
+ *		an error.  Hence before calling this function, callers should make sure
+ *		that the slot type is the one that supports system attributes, namely,
+ *		heap tuple slot and buffer tuple slot.
+ */
+static inline Datum
+slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
+{
+	AssertArg(attnum < 0);		/* caller error */
+
+	/* Fetch the system attribute from the underlying tuple. */
+	return slot->tts_cb->getsysattr(slot, attnum, isnull);
+}
+
+/*
+ * ExecClearTuple
+ *
+ * A thin wrapper around calling TupleTableSlotType specific clear() method.
+ */
+static inline TupleTableSlot *
+ExecClearTuple(TupleTableSlot *slot)
+{
+	slot->tts_cb->clear(slot);
+
+	return slot;
+}
+
+/* ExecMaterializeSlot - force a slot into the "materialized" state.
+ *
+ * This causes the slot's tuple to be a local copy not dependent on any
+ * external storage (i.e. pointing into a Buffer, or having allocations in
+ * another memory context).
+ *
+ * A typical use for this operation is to prepare a computed tuple for being
+ * stored on disk.  The original data may or may not be virtual, but in any
+ * case we need a private copy for heap_insert to scribble on.
+ */
+static inline void
+ExecMaterializeSlot(TupleTableSlot *slot)
+{
+	slot->tts_cb->materialize(slot);
+}
+
+/*
+ * ExecCopySlotTuple
+ *
+ * A thin wrapper calling TupleTableSlotType specific copy_heap_tuple()
+ * method.
+ */
+static inline HeapTuple
+ExecCopySlotTuple(TupleTableSlot *slot)
+{
+	/*
+	 * sanity checks
+	 */
+	Assert(slot != NULL);
+	Assert(!TTS_EMPTY(slot));
+
+	return slot->tts_cb->copy_heap_tuple(slot);
+}
+
+/*
+ * ExecCopySlotMinimalTuple
+ *
+ * A thin wrapper around calling TupleTableSlotType specific
+ * copy_minimal_tuple() method.
+ */
+static inline MinimalTuple
+ExecCopySlotMinimalTuple(TupleTableSlot *slot)
+{
+	return slot->tts_cb->copy_minimal_tuple(slot);
+}
+
+/*
+ * ExecCopySlot
+ *
+ * A thin wrapper calling TupleTableSlotType specific copyslot callback.
+ *
+ * The caller must ensure the slots have compatible tupdescs.
+ */
+static inline TupleTableSlot *
+ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
+{
+	dstslot->tts_cb->copyslot(dstslot, srcslot);
+
+	return dstslot;
+}
+
+#endif							/* FRONTEND */
 
 #endif							/* TUPTABLE_H */
diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h
index f3ea2492835..b4b0a16d1ae 100644
--- a/src/include/jit/llvmjit.h
+++ b/src/include/jit/llvmjit.h
@@ -65,6 +65,8 @@ extern LLVMTypeRef TypeStorageBool;
 extern LLVMTypeRef StructtupleDesc;
 extern LLVMTypeRef StructHeapTupleData;
 extern LLVMTypeRef StructTupleTableSlot;
+extern LLVMTypeRef StructHeapTupleTableSlot;
+extern LLVMTypeRef StructMinimalTupleTableSlot;
 extern LLVMTypeRef StructMemoryContextData;
 extern LLVMTypeRef StructFunctionCallInfoData;
 extern LLVMTypeRef StructExprContext;
@@ -77,7 +79,7 @@ extern LLVMTypeRef StructAggStatePerGroupData;
 extern LLVMValueRef AttributeTemplate;
 extern LLVMValueRef FuncStrlen;
 extern LLVMValueRef FuncVarsizeAny;
-extern LLVMValueRef FuncSlotGetsomeattrs;
+extern LLVMValueRef FuncSlotGetsomeattrsInt;
 extern LLVMValueRef FuncSlotGetmissingattrs;
 extern LLVMValueRef FuncMakeExpandedObjectReadOnlyInternal;
 extern LLVMValueRef FuncExecEvalArrayRefSubscript;
@@ -111,7 +113,8 @@ extern void llvm_inline(LLVMModuleRef mod);
  ****************************************************************************
  */
 extern bool llvm_compile_expr(struct ExprState *state);
-extern LLVMValueRef slot_compile_deform(struct LLVMJitContext *context, TupleDesc desc, int natts);
+struct TupleTableSlotOps;
+extern LLVMValueRef slot_compile_deform(struct LLVMJitContext *context, TupleDesc desc, const struct TupleTableSlotOps *ops, int natts);
 
 /*
  ****************************************************************************
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 59fb3c15833..149916093a2 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1100,6 +1100,7 @@ typedef struct ModifyTableState
 	PlanState **mt_plans;		/* subplans (one per target rel) */
 	int			mt_nplans;		/* number of plans in the array */
 	int			mt_whichplan;	/* which one is being executed (0..n-1) */
+	TupleTableSlot** mt_scans;	/* input tuple for underlying plan */
 	ResultRelInfo *resultRelInfo;	/* per-subplan target relations */
 	ResultRelInfo *rootResultRelInfo;	/* root target relation (partitioned
 										 * table root) */
-- 
2.18.0.rc2.dirty


--ll5lqoiis2grgqzk
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="v14-0007-Rationalize-expression-context-reset-in-ExecModi.patch"



^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v2 1/4] Make stack depth check work with asan's use-after-return
@ 2026-02-07 19:04 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-02-07 19:04 UTC (permalink / raw)

With address sanitizer's stack-use-after-return check, stack variables are
moved to heap allocations, to allow to detect references to the memory at a
later time. That broke our stack-depth check, which is why we had to disable
detect_stack_use_after_return in CI. Luckily __builtin_frame_address() works
correctly, even under asan, so use that.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/utils/misc/stack_depth.c | 17 ++++++++++++++++-
 .cirrus.tasks.yml                    |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/misc/stack_depth.c b/src/backend/utils/misc/stack_depth.c
index 61a07cf824e..9955e28c176 100644
--- a/src/backend/utils/misc/stack_depth.c
+++ b/src/backend/utils/misc/stack_depth.c
@@ -108,13 +108,28 @@ check_stack_depth(void)
 bool
 stack_is_too_deep(void)
 {
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
 	char		stack_top_loc;
+#endif
 	ssize_t		stack_depth;
+	char	   *stack_address;
+
+	/*
+	 * With address sanitizer's stack-use-after-return check, stack variables
+	 * are moved to heap allocations, to allow to detect references to the
+	 * memory at a later time. That would break our stack-depth check. Luckily
+	 * __builtin_frame_address() works correctly, even under asan.
+	 */
+#ifndef HAVE__BUILTIN_FRAME_ADDRESS
+	stack_address = &stack_top_loc;
+#else
+	stack_address = (char *) __builtin_frame_address(0);
+#endif
 
 	/*
 	 * Compute distance from reference point to my local variables
 	 */
-	stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
+	stack_depth = (ssize_t) (stack_base_ptr - stack_address);
 
 	/*
 	 * Take abs value, since stacks grow up on some machines, down on others
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
index a22cef063f3..8683d1ae9c7 100644
--- a/.cirrus.tasks.yml
+++ b/.cirrus.tasks.yml
@@ -447,7 +447,7 @@ task:
     # print_stacktraces=1,verbosity=2, duh
     # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
     UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0:detect_stack_use_after_return=0
+    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
 
     # SANITIZER_FLAGS is set in the tasks below
     CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-- 
2.53.0.1.gb2826b52eb


--7e2sypi5gxvkgog6--





^ permalink  raw  reply  [nested|flat] 114+ messages in thread

* [PATCH v9a 03/22] ci: Remove support for cirrus-ci based CI
@ 2026-05-28 17:31 Andres Freund <[email protected]>
  0 siblings, 0 replies; 114+ messages in thread

From: Andres Freund @ 2026-05-28 17:31 UTC (permalink / raw)

As mentioned in the earlier commit, cirrus-ci has shut down. Therefore remove
all files related to running CI via cirrus. Also update comments / code that
were referencing cirrus-ci.

Discussion: https://postgr.es/m/3ydjipcr7kbss57nvi67noplncqhesl5eyb6wgol4ccjxynspv%40yatlykpribmm
---
 src/bin/pg_combinebackup/t/010_hardlink.pl |   12 +-
 .cirrus.yml                                |   91 --
 src/test/perl/PostgreSQL/Test/Cluster.pm   |    5 +-
 .cirrus.star                               |  143 ---
 .cirrus.tasks.yml                          | 1022 --------------------
 src/tools/ci/ci_macports_packages.sh       |    6 +-
 src/tools/ci/gcp_ram_disk.sh               |   27 -
 7 files changed, 11 insertions(+), 1295 deletions(-)
 delete mode 100644 .cirrus.yml
 delete mode 100644 .cirrus.star
 delete mode 100644 .cirrus.tasks.yml
 delete mode 100755 src/tools/ci/gcp_ram_disk.sh

diff --git a/src/bin/pg_combinebackup/t/010_hardlink.pl b/src/bin/pg_combinebackup/t/010_hardlink.pl
index b6e8a9128af..5fbbe6a923b 100644
--- a/src/bin/pg_combinebackup/t/010_hardlink.pl
+++ b/src/bin/pg_combinebackup/t/010_hardlink.pl
@@ -18,13 +18,13 @@ $primary->append_conf('postgresql.conf', 'autovacuum = off');
 $primary->start;
 
 # Create a couple of tables (~264KB each).
-# Note: Cirrus CI runs some tests with a very small segment size, so, in that
+# Note: CI runs some tests with a very small segment size, so, in that
 # environment, a single table of 264KB would have both a segment with a link
-# count of 1 and also one with a link count of 2. But in a normal installation,
-# segment size is 1GB.  Therefore, we use 2 different tables here: for test_1,
-# all segments (or the only one) will have two hard links; for test_2, the
-# last segment (or the only one) will have 1 hard link, and any others will
-# have 2.
+# count of 1 and also one with a link count of 2. But in a normal
+# installation, segment size is 1GB.  Therefore, we use 2 different tables
+# here: for test_1, all segments (or the only one) will have two hard links;
+# for test_2, the last segment (or the only one) will have 1 hard link, and
+# any others will have 2.
 my $query = <<'EOM';
 CREATE TABLE test_%s AS
     SELECT x.id::bigint,
diff --git a/.cirrus.yml b/.cirrus.yml
deleted file mode 100644
index 3f75852e84e..00000000000
--- a/.cirrus.yml
+++ /dev/null
@@ -1,91 +0,0 @@
-# CI configuration file for CI utilizing cirrus-ci.org
-#
-# For instructions on how to enable the CI integration in a repository and
-# further details, see src/tools/ci/README
-#
-#
-# The actual CI tasks are defined in .cirrus.tasks.yml. To make the compute
-# resources for CI configurable on a repository level, the "final" CI
-# configuration is the combination of:
-#
-# 1) the contents of this file
-#
-# 2) computed environment variables
-#
-#    Used to enable/disable tasks based on the execution environment. See
-#    .cirrus.star: compute_environment_vars()
-#
-# 3) if defined, the contents of the file referenced by the, repository
-#    level, REPO_CI_CONFIG_GIT_URL variable (see
-#    https://cirrus-ci.org/guide/programming-tasks/#fs for the accepted
-#    format)
-#
-#    This allows running tasks in a different execution environment than the
-#    default, e.g. to have sufficient resources for cfbot.
-#
-# 4) .cirrus.tasks.yml
-#
-# This composition is done by .cirrus.star
-
-
-env:
-  # Source of images / containers
-  GCP_PROJECT: pg-ci-images
-  IMAGE_PROJECT: $GCP_PROJECT
-  CONTAINER_REPO: us-docker.pkg.dev/${GCP_PROJECT}/ci
-  DISK_SIZE: 25
-
-
-# Define how to run various types of tasks.
-
-# VMs provided by cirrus-ci. Each user has a limited number of "free" credits
-# for testing.
-cirrus_community_vm_template: &cirrus_community_vm_template
-  compute_engine_instance:
-    image_project: $IMAGE_PROJECT
-    image: family/$IMAGE_FAMILY
-    platform: $PLATFORM
-    cpu: $CPUS
-    disk: $DISK_SIZE
-
-
-default_linux_task_template: &linux_task_template
-  env:
-    PLATFORM: linux
-  <<: *cirrus_community_vm_template
-
-
-default_freebsd_task_template: &freebsd_task_template
-  env:
-    PLATFORM: freebsd
-  <<: *cirrus_community_vm_template
-
-default_netbsd_task_template: &netbsd_task_template
-  env:
-    PLATFORM: netbsd
-  <<: *cirrus_community_vm_template
-
-default_openbsd_task_template: &openbsd_task_template
-  env:
-    PLATFORM: openbsd
-  <<: *cirrus_community_vm_template
-
-
-default_windows_task_template: &windows_task_template
-  env:
-    PLATFORM: windows
-  <<: *cirrus_community_vm_template
-
-
-# macos workers provided by cirrus-ci
-default_macos_task_template: &macos_task_template
-  env:
-    PLATFORM: macos
-  macos_instance:
-    image: $IMAGE
-
-
-# Contents of REPO_CI_CONFIG_GIT_URL, if defined, will be inserted here,
-# followed by the contents .cirrus.tasks.yml. This allows
-# REPO_CI_CONFIG_GIT_URL to override how the task types above will be
-# executed, e.g. using a custom compute account or permanent workers.
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index 4fcb1f6be56..529f49efee1 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -363,9 +363,8 @@ This tries to connect to the server, to test whether it works or not,,
 so the server is up and running. Otherwise this can return 0 even if
 there's nothing wrong with raw_connect() itself.
 
-Notably, raw_connect() does not work on Unix domain sockets on
-Strawberry perl 5.26.3.1 on Windows, which we use in Cirrus CI images
-as of this writing. It dies with "not implemented on this
+Notably, raw_connect() does not work on Unix domain sockets on at least
+Strawberry perl 5.26.3.1 on Windows. It dies with "not implemented on this
 architecture".
 
 =cut
diff --git a/.cirrus.star b/.cirrus.star
deleted file mode 100644
index e9bb672b959..00000000000
--- a/.cirrus.star
+++ /dev/null
@@ -1,143 +0,0 @@
-"""Additional CI configuration, using the starlark language. See
-https://cirrus-ci.org/guide/programming-tasks/#introduction-into-starlark
-
-See also the starlark specification at
-https://github.com/bazelbuild/starlark/blob/master/spec.md
-
-See also .cirrus.yml and src/tools/ci/README
-"""
-
-load("cirrus", "env", "fs", "re", "yaml")
-
-
-def main():
-    """The main function is executed by cirrus-ci after loading .cirrus.yml and can
-    extend the CI definition further.
-
-    As documented in .cirrus.yml, the final CI configuration is composed of
-
-    1) the contents of .cirrus.yml
-
-    2) computed environment variables
-
-    3) if defined, the contents of the file referenced by the, repository
-       level, REPO_CI_CONFIG_GIT_URL variable (see
-       https://cirrus-ci.org/guide/programming-tasks/#fs for the accepted
-       format)
-
-    4) .cirrus.tasks.yml
-    """
-
-    output = ""
-
-    # 1) is evaluated implicitly
-
-
-    # Add 2)
-    additional_env = compute_environment_vars()
-    env_fmt = """
-###
-# Computed environment variables start here
-###
-{0}
-###
-# Computed environment variables end here
-###
-"""
-    output += env_fmt.format(yaml.dumps({'env': additional_env}))
-
-
-    # Add 3)
-    repo_config_url = env.get("REPO_CI_CONFIG_GIT_URL")
-    if repo_config_url != None:
-        print("loading additional configuration from \"{}\"".format(repo_config_url))
-        output += config_from(repo_config_url)
-    else:
-        output += "\n# REPO_CI_CONFIG_URL was not set\n"
-
-
-    # Add 4)
-    output += config_from(".cirrus.tasks.yml")
-
-
-    return output
-
-
-def compute_environment_vars():
-    cenv = {}
-
-    ###
-    # Some tasks are manually triggered by default because they might use too
-    # many resources for users of free Cirrus credits, but they can be
-    # triggered automatically by naming them in an environment variable e.g.
-    # REPO_CI_AUTOMATIC_TRIGGER_TASKS="task_name other_task" under "Repository
-    # Settings" on Cirrus CI's website.
-
-    default_manual_trigger_tasks = ['mingw', 'netbsd', 'openbsd']
-
-    repo_ci_automatic_trigger_tasks = env.get('REPO_CI_AUTOMATIC_TRIGGER_TASKS', '')
-    for task in default_manual_trigger_tasks:
-        name = 'CI_TRIGGER_TYPE_' + task.upper()
-        if repo_ci_automatic_trigger_tasks.find(task) != -1:
-            value = 'automatic'
-        else:
-            value = 'manual'
-        cenv[name] = value
-    ###
-
-    ###
-    # Parse "ci-os-only:" tag in commit message and set
-    # CI_{$OS}_ENABLED variable for each OS
-
-    # We want to disable SanityCheck if testing just a specific OS. This
-    # shortens push-wait-for-ci cycle time a bit when debugging operating
-    # system specific failures. Just treating it as an OS in that case
-    # suffices.
-
-    operating_systems = [
-      'compilerwarnings',
-      'freebsd',
-      'linux',
-      'macos',
-      'mingw',
-      'netbsd',
-      'openbsd',
-      'sanitycheck',
-      'windows',
-    ]
-    commit_message = env.get('CIRRUS_CHANGE_MESSAGE')
-    match_re = r"(^|.*\n)ci-os-only: ([^\n]+)($|\n.*)"
-
-    # re.match() returns an array with a tuple of (matched-string, match_1, ...)
-    m = re.match(match_re, commit_message)
-    if m and len(m) > 0:
-        os_only = m[0][2]
-        os_only_list = re.split(r'[, ]+', os_only)
-    else:
-        os_only_list = operating_systems
-
-    for os in operating_systems:
-        os_enabled = os in os_only_list
-        cenv['CI_{0}_ENABLED'.format(os.upper())] = os_enabled
-    ###
-
-    return cenv
-
-
-def config_from(config_src):
-    """return contents of config file `config_src`, surrounded by markers
-    indicating start / end of the included file
-    """
-
-    config_contents = fs.read(config_src)
-    config_fmt = """
-
-###
-# contents of config file `{0}` start here
-###
-{1}
-###
-# contents of config file `{0}` end here
-###
-"""
-    return config_fmt.format(config_src, config_contents)
diff --git a/.cirrus.tasks.yml b/.cirrus.tasks.yml
deleted file mode 100644
index 8683d1ae9c7..00000000000
--- a/.cirrus.tasks.yml
+++ /dev/null
@@ -1,1022 +0,0 @@
-# CI configuration file for CI utilizing cirrus-ci.org
-#
-# For instructions on how to enable the CI integration in a repository and
-# further details, see src/tools/ci/README
-#
-#
-# NB: Different tasks intentionally test with different, non-default,
-# configurations, to increase the chance of catching problems. Each task with
-# non-obvious non-default documents their oddity at the top of the task,
-# prefixed by "SPECIAL:".
-
-
-env:
-  # The lower depth accelerates git clone. Use a bit of depth so that
-  # concurrent tasks and retrying older jobs have a chance of working.
-  CIRRUS_CLONE_DEPTH: 500
-  # Useful to be able to analyse what in a script takes long
-  CIRRUS_LOG_TIMESTAMP: true
-
-  CCACHE_MAXSIZE: "250M"
-
-  # target to test, for all but windows
-  CHECK: check-world PROVE_FLAGS=$PROVE_FLAGS
-  CHECKFLAGS: -Otarget
-  PROVE_FLAGS: --timer
-  # Build test dependencies as part of the build step, to see compiler
-  # errors/warnings in one place.
-  MBUILD_TARGET: all testprep
-  MTEST_ARGS: --print-errorlogs --no-rebuild -C build
-  PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests
-  TEMP_CONFIG: ${CIRRUS_WORKING_DIR}/src/tools/ci/pg_ci_base.conf
-  PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth
-
-  # Postgres config args for the meson builds, shared between all meson tasks
-  # except the 'SanityCheck' task
-  MESON_COMMON_PG_CONFIG_ARGS: -Dcassert=true -Dinjection_points=true
-
-  # Meson feature flags shared by all meson tasks, except:
-  # SanityCheck: uses almost no dependencies.
-  # Windows - VS: has fewer dependencies than listed here, so defines its own.
-  # Linux: uses the 'auto' feature option to test meson feature autodetection.
-  MESON_COMMON_FEATURES: >-
-    -Dauto_features=disabled
-    -Dldap=enabled
-    -Dssl=openssl
-    -Dtap_tests=enabled
-    -Dplperl=enabled
-    -Dplpython=enabled
-    -Ddocs=enabled
-    -Dicu=enabled
-    -Dlibxml=enabled
-    -Dlibxslt=enabled
-    -Dlz4=enabled
-    -Dpltcl=enabled
-    -Dreadline=enabled
-    -Dzlib=enabled
-    -Dzstd=enabled
-
-
-# What files to preserve in case tests fail
-on_failure_ac: &on_failure_ac
-  log_artifacts:
-    paths:
-      - "**/*.log"
-      - "**/*.diffs"
-      - "**/regress_log_*"
-    type: text/plain
-
-on_failure_meson: &on_failure_meson
-  testrun_artifacts:
-    paths:
-      - "build*/testrun/**/*.log"
-      - "build*/testrun/**/*.diffs"
-      - "build*/testrun/**/regress_log_*"
-    type: text/plain
-
-  # In theory it'd be nice to upload the junit files meson generates, so that
-  # cirrus will nicely annotate the commit. Unfortunately the files don't
-  # contain identifiable file + line numbers right now, so the annotations
-  # don't end up useful. We could probably improve on that with a some custom
-  # conversion script, but ...
-  meson_log_artifacts:
-    path: "build*/meson-logs/*.txt"
-    type: text/plain
-
-
-# To avoid unnecessarily spinning up a lot of VMs / containers for entirely
-# broken commits, have a minimal task that all others depend on.
-#
-# SPECIAL:
-# - Builds with --auto-features=disabled and thus almost no enabled
-#   dependencies
-task:
-  name: SanityCheck
-
-  # If a specific OS is requested, don't run the sanity check. This shortens
-  # push-wait-for-ci cycle time a bit when debugging operating system specific
-  # failures. Uses skip instead of only_if, as cirrus otherwise warns about
-  # only_if conditions not matching.
-  skip: $CI_SANITYCHECK_ENABLED == false
-
-  env:
-    CPUS: 4
-    BUILD_JOBS: 8
-    TEST_JOBS: 8
-    IMAGE_FAMILY: pg-ci-trixie
-    CCACHE_DIR: ${CIRRUS_WORKING_DIR}/ccache_dir
-    # no options enabled, should be small
-    CCACHE_MAXSIZE: "150M"
-
-  # While containers would start up a bit quicker, building is a bit
-  # slower. This way we don't have to maintain a container image.
-  <<: *linux_task_template
-
-  ccache_cache:
-    folder: $CCACHE_DIR
-
-  create_user_script: |
-    useradd -m postgres
-    chown -R postgres:postgres .
-    mkdir -p ${CCACHE_DIR}
-    chown -R postgres:postgres ${CCACHE_DIR}
-    echo '* - memlock 134217728' > /etc/security/limits.d/postgres.conf
-    su postgres -c "ulimit -l -H && ulimit -l -S"
-    # Can't change container's kernel.core_pattern. Postgres user can't write
-    # to / normally. Change that.
-    chown root:postgres /
-    chmod g+rwx /
-
-  configure_script: |
-    su postgres <<-EOF
-      set -e
-      meson setup \
-        --buildtype=debug \
-        --auto-features=disabled \
-        -Ddefault_library=shared \
-        -Dtap_tests=enabled \
-        build
-    EOF
-  build_script: |
-    su postgres <<-EOF
-      set -e
-      ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET}
-    EOF
-  upload_caches: ccache
-
-  # Run a minimal set of tests. The main regression tests take too long for
-  # this purpose. For now this is a random quick pg_regress style test, and a
-  # tap test that exercises both a frontend binary and the backend.
-  test_minimal_script: |
-    su postgres <<-EOF
-      set -e
-      ulimit -c unlimited
-      meson test $MTEST_ARGS --suite setup
-      meson test $MTEST_ARGS --num-processes ${TEST_JOBS} \
-        cube/regress pg_ctl/001_start_stop
-    EOF
-
-  on_failure:
-    <<: *on_failure_meson
-    cores_script: |
-      mkdir -m 770 /tmp/cores
-      find / -maxdepth 1 -type f -name 'core*' -exec mv '{}' /tmp/cores/ \;
-      src/tools/ci/cores_backtrace.sh linux /tmp/cores
-
-
-# SPECIAL:
-# - Uses postgres specific CPPFLAGS that increase test coverage
-# - Specifies configuration options that test reading/writing/copying of node trees
-# - Specifies debug_parallel_query=regress, to catch related issues during CI
-# - Also runs tests against a running postgres instance, see test_running_script
-task:
-  name: FreeBSD - Meson
-
-  env:
-    CPUS: 4
-    BUILD_JOBS: 4
-    TEST_JOBS: 8
-    IMAGE_FAMILY: pg-ci-freebsd
-    DISK_SIZE: 50
-
-    CCACHE_DIR: /tmp/ccache_dir
-    CPPFLAGS: -DRELCACHE_FORCE_RELEASE -DENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
-    CFLAGS: -Og -ggdb
-
-    # Several buildfarm animals enable these options. Without testing them
-    # during CI, it would be easy to cause breakage on the buildfarm with CI
-    # passing.
-    PG_TEST_INITDB_EXTRA_OPTS: >-
-      -c debug_copy_parse_plan_trees=on
-      -c debug_write_read_parse_plan_trees=on
-      -c debug_raw_expression_coverage_test=on
-      -c debug_parallel_query=regress
-    PG_TEST_PG_UPGRADE_MODE: --link
-
-    MESON_FEATURES: >-
-      -Ddtrace=enabled
-      -Dgssapi=enabled
-      -Dlibcurl=enabled
-      -Dnls=enabled
-      -Dpam=enabled
-      -Dtcl_version=tcl86
-      -Duuid=bsd
-
-  <<: *freebsd_task_template
-
-  depends_on: SanityCheck
-  only_if: $CI_FREEBSD_ENABLED
-
-  sysinfo_script: |
-    id
-    uname -a
-    ulimit -a -H && ulimit -a -S
-    export
-
-  ccache_cache:
-    folder: $CCACHE_DIR
-  setup_ram_disk_script: src/tools/ci/gcp_ram_disk.sh
-  create_user_script: |
-    pw useradd postgres
-    chown -R postgres:postgres .
-    mkdir -p ${CCACHE_DIR}
-    chown -R postgres:postgres ${CCACHE_DIR}
-  setup_core_files_script: |
-    mkdir -m 770 /tmp/cores
-    chown root:postgres /tmp/cores
-    sysctl kern.corefile='/tmp/cores/%N.%P.core'
-  setup_additional_packages_script: |
-    #pkg install -y ...
-
-  # NB: Intentionally build without -Dllvm. The freebsd image size is already
-  # large enough to make VM startup slow, and even without llvm freebsd
-  # already takes longer than other platforms except for windows.
-  configure_script: |
-    su postgres <<-EOF
-      set -e
-      meson setup \
-        ${MESON_COMMON_PG_CONFIG_ARGS} \
-        --buildtype=debug \
-        -Dextra_lib_dirs=/usr/local/lib -Dextra_include_dirs=/usr/local/include/ \
-        ${MESON_COMMON_FEATURES} ${MESON_FEATURES} \
-        build
-    EOF
-  build_script: su postgres -c 'ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET}'
-  upload_caches: ccache
-
-  test_world_script: |
-    su postgres <<-EOF
-      set -e
-      ulimit -c unlimited
-      meson test $MTEST_ARGS --num-processes ${TEST_JOBS}
-    EOF
-
-  # test runningcheck, freebsd chosen because it's currently fast enough
-  test_running_script: |
-    su postgres <<-EOF
-      set -e
-      ulimit -c unlimited
-      meson test $MTEST_ARGS --quiet --suite setup
-      export LD_LIBRARY_PATH="$(pwd)/build/tmp_install/usr/local/pgsql/lib/:$LD_LIBRARY_PATH"
-      mkdir -p build/testrun
-      build/tmp_install/usr/local/pgsql/bin/initdb -N build/runningcheck --no-instructions -A trust
-      echo "include '$(pwd)/src/tools/ci/pg_ci_base.conf'" >> build/runningcheck/postgresql.conf
-      build/tmp_install/usr/local/pgsql/bin/pg_ctl -c -o '-c fsync=off' -D build/runningcheck -l build/testrun/runningcheck.log start
-      meson test $MTEST_ARGS --num-processes ${TEST_JOBS} --setup running
-      build/tmp_install/usr/local/pgsql/bin/pg_ctl -D build/runningcheck stop
-    EOF
-
-  on_failure:
-    # if the server continues running, it often causes cirrus-ci to fail
-    # during upload, as it doesn't expect artifacts to change size
-    stop_running_script: |
-      su postgres <<-EOF
-        set -e
-        build/tmp_install/usr/local/pgsql/bin/pg_ctl -D build/runningcheck stop || true
-      EOF
-    <<: *on_failure_meson
-    cores_script: src/tools/ci/cores_backtrace.sh freebsd /tmp/cores
-
-
-task:
-  depends_on: SanityCheck
-
-  env:
-    # Below are experimentally derived to be a decent choice.
-    CPUS: 4
-    BUILD_JOBS: 8
-    TEST_JOBS: 8
-
-    # Default working directory is /tmp, but its total size (1.2 GB) is not
-    # enough, so different working and cache directory are set.
-    CIRRUS_WORKING_DIR: /home/postgres/postgres
-    CCACHE_DIR: /home/postgres/cache
-
-    PATH: /usr/sbin:$PATH
-    CORE_DUMP_DIR: /var/crash
-
-  matrix:
-    - name: NetBSD - Meson
-      # See REPO_CI_AUTOMATIC_TRIGGER_TASKS in .cirrus.star
-      trigger_type: $CI_TRIGGER_TYPE_NETBSD
-      only_if: $CI_NETBSD_ENABLED
-      env:
-        OS_NAME: netbsd
-        IMAGE_FAMILY: pg-ci-netbsd-postgres
-        PKGCONFIG_PATH: '/usr/lib/pkgconfig:/usr/pkg/lib/pkgconfig'
-        # initdb fails with: 'invalid locale settings' error on NetBSD.
-        # Force 'LANG' and 'LC_*' variables to be 'C'.
-        # See https://postgr.es/m/2490325.1734471752%40sss.pgh.pa.us
-        LANG: "C"
-        LC_ALL: "C"
-        # -Duuid is not set for the NetBSD, see the comment below, above
-        # configure_script, for more information.
-        MESON_FEATURES: >-
-          -Dgssapi=enabled
-          -Dlibcurl=enabled
-          -Dnls=enabled
-          -Dpam=enabled
-
-      setup_additional_packages_script: |
-        #pkgin -y install ...
-      <<: *netbsd_task_template
-
-    - name: OpenBSD - Meson
-      # See REPO_CI_AUTOMATIC_TRIGGER_TASKS in .cirrus.star
-      trigger_type: $CI_TRIGGER_TYPE_OPENBSD
-      only_if: $CI_OPENBSD_ENABLED
-      env:
-        OS_NAME: openbsd
-        IMAGE_FAMILY: pg-ci-openbsd-postgres
-        PKGCONFIG_PATH: '/usr/lib/pkgconfig:/usr/local/lib/pkgconfig'
-        CORE_DUMP_EXECUTABLE_DIR: $CIRRUS_WORKING_DIR/build/tmp_install/usr/local/pgsql/bin
-
-        MESON_FEATURES: >-
-          -Dbsd_auth=enabled
-          -Dlibcurl=enabled
-          -Dtcl_version=tcl86
-          -Duuid=e2fs
-
-      setup_additional_packages_script: |
-        #pkg_add -I ...
-      # Always core dump to ${CORE_DUMP_DIR}
-      set_core_dump_script: sysctl -w kern.nosuidcoredump=2
-      <<: *openbsd_task_template
-
-  sysinfo_script: |
-    locale
-    id
-    uname -a
-    ulimit -a -H && ulimit -a -S
-    env
-
-  ccache_cache:
-    folder: $CCACHE_DIR
-  setup_ram_disk_script: src/tools/ci/gcp_ram_disk.sh
-  create_user_script: |
-    useradd postgres
-    chown -R postgres:users /home/postgres
-    mkdir -p ${CCACHE_DIR}
-    chown -R postgres:users ${CCACHE_DIR}
-  setup_core_files_script: |
-    mkdir -p ${CORE_DUMP_DIR}
-    chmod -R 770 ${CORE_DUMP_DIR}
-    chown -R postgres:users ${CORE_DUMP_DIR}
-
-  # -Duuid=bsd is not set since 'bsd' uuid option
-  # is not working on NetBSD & OpenBSD. See
-  # https://www.postgresql.org/message-id/[email protected]
-  # And other uuid options are not available on NetBSD.
-  configure_script: |
-    su postgres <<-EOF
-      set -e
-      meson setup \
-        ${MESON_COMMON_PG_CONFIG_ARGS} \
-        --buildtype=debugoptimized \
-        --pkg-config-path ${PKGCONFIG_PATH} \
-        ${MESON_COMMON_FEATURES} ${MESON_FEATURES} \
-        build
-    EOF
-
-  build_script: su postgres -c 'ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET}'
-  upload_caches: ccache
-
-  test_world_script: |
-    su postgres <<-EOF
-      set -e
-      ulimit -c unlimited
-      meson test $MTEST_ARGS --num-processes ${TEST_JOBS}
-    EOF
-
-  on_failure:
-    <<: *on_failure_meson
-    cores_script: |
-      # Although we try to configure the OS to core dump inside
-      # ${CORE_DUMP_DIR}, they may not obey this. So, move core files to the
-      # ${CORE_DUMP_DIR} directory.
-      find build/ -type f -name '*.core' -exec mv '{}' ${CORE_DUMP_DIR} \;
-      src/tools/ci/cores_backtrace.sh ${OS_NAME} ${CORE_DUMP_DIR} ${CORE_DUMP_EXECUTABLE_DIR}
-
-
-# configure feature flags, shared between the task running the linux tests and
-# the CompilerWarnings task
-LINUX_CONFIGURE_FEATURES: &LINUX_CONFIGURE_FEATURES >-
-  --with-gssapi
-  --with-icu
-  --with-ldap
-  --with-libcurl
-  --with-libxml
-  --with-libxslt
-  --with-llvm
-  --with-lz4
-  --with-pam
-  --with-perl
-  --with-python
-  --with-selinux
-  --with-ssl=openssl
-  --with-systemd
-  --with-tcl --with-tclconfig=/usr/lib/tcl8.6/
-  --with-uuid=ossp
-  --with-zstd
-
-
-# Check SPECIAL in the matrix: below
-task:
-  env:
-    CPUS: 4
-    BUILD_JOBS: 4
-    TEST_JOBS: 8 # experimentally derived to be a decent choice
-    IMAGE_FAMILY: pg-ci-trixie
-
-    CCACHE_DIR: /tmp/ccache_dir
-    DEBUGINFOD_URLS: "https://debuginfod.debian.net";
-
-    # Enable a reasonable set of sanitizers. Use the linux task for that, as
-    # it's one of the fastest tasks (without sanitizers). Also several of the
-    # sanitizers work best on linux.
-    #
-    # The overhead of alignment sanitizer is low, undefined behaviour has
-    # moderate overhead. Test alignment sanitizer in the meson task, as it
-    # does both 32 and 64 bit builds and is thus more likely to expose
-    # alignment bugs.
-    #
-    # Address sanitizer in contrast is somewhat expensive. Enable it in the
-    # autoconf task, as the meson task tests both 32 and 64bit.
-    #
-    # disable_coredump=0, abort_on_error=1: for useful backtraces in case of crashes
-    # print_stacktraces=1,verbosity=2, duh
-    # detect_leaks=0: too many uninteresting leak errors in short-lived binaries
-    UBSAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:verbosity=2
-    ASAN_OPTIONS: print_stacktrace=1:disable_coredump=0:abort_on_error=1:detect_leaks=0
-
-    # SANITIZER_FLAGS is set in the tasks below
-    CFLAGS: -Og -ggdb -fno-sanitize-recover=all $SANITIZER_FLAGS
-    CXXFLAGS: $CFLAGS
-    LDFLAGS: $SANITIZER_FLAGS
-    CC: ccache gcc
-    CXX: ccache g++
-
-    LINUX_CONFIGURE_FEATURES: *LINUX_CONFIGURE_FEATURES
-    LINUX_MESON_FEATURES: >-
-      -Duuid=e2fs
-
-  <<: *linux_task_template
-
-  depends_on: SanityCheck
-  only_if: $CI_LINUX_ENABLED
-
-  ccache_cache:
-    folder: ${CCACHE_DIR}
-
-  sysinfo_script: |
-    id
-    uname -a
-    cat /proc/cmdline
-    ulimit -a -H && ulimit -a -S
-    export
-  create_user_script: |
-    useradd -m postgres
-    chown -R postgres:postgres .
-    mkdir -p ${CCACHE_DIR}
-    chown -R postgres:postgres ${CCACHE_DIR}
-    echo '* - memlock 134217728' > /etc/security/limits.d/postgres.conf
-    su postgres -c "ulimit -l -H && ulimit -l -S"
-  setup_core_files_script: |
-    mkdir -m 770 /tmp/cores
-    chown root:postgres /tmp/cores
-    sysctl kernel.core_pattern='/tmp/cores/%e-%s-%p.core'
-
-  setup_hosts_file_script: |
-    cat >> /etc/hosts <<-EOF
-      127.0.0.1 pg-loadbalancetest
-      127.0.0.2 pg-loadbalancetest
-      127.0.0.3 pg-loadbalancetest
-    EOF
-
-  setup_additional_packages_script: |
-    #apt-get update
-    #DEBIAN_FRONTEND=noninteractive apt-get -y install ...
-
-  matrix:
-    # SPECIAL:
-    # - Uses address sanitizer, sanitizer failures are typically printed in
-    #   the server log
-    # - Configures postgres with a small segment size
-    - name: Linux - Debian Trixie - Autoconf
-
-      env:
-        SANITIZER_FLAGS: -fsanitize=address
-        PG_TEST_PG_COMBINEBACKUP_MODE: --copy-file-range
-
-      # Normally, the "relation segment" code basically has no coverage in our
-      # tests, because we (quite reasonably) don't generate tables large
-      # enough in tests. We've had plenty bugs that we didn't notice due the
-      # code not being exercised much. Thus specify a very small segment size
-      # here. Use a non-power-of-two segment size, given we currently allow
-      # that.
-      configure_script: |
-        su postgres <<-EOF
-          set -e
-          ./configure \
-            --enable-cassert --enable-injection-points --enable-debug \
-            --enable-tap-tests --enable-nls \
-            --with-segsize-blocks=6 \
-            --with-libnuma \
-            --with-liburing \
-            \
-            ${LINUX_CONFIGURE_FEATURES} \
-            \
-            CLANG="ccache clang"
-        EOF
-      build_script: su postgres -c "make -s -j${BUILD_JOBS} world-bin"
-      upload_caches: ccache
-
-      test_world_script: |
-        su postgres <<-EOF
-          set -e
-          ulimit -c unlimited # default is 0
-          make -s ${CHECK} ${CHECKFLAGS} -j${TEST_JOBS}
-        EOF
-
-      on_failure:
-        <<: *on_failure_ac
-
-    # SPECIAL:
-    # - Uses undefined behaviour and alignment sanitizers, sanitizer failures
-    #   are typically printed in the server log
-    # - Test both 64bit and 32 bit builds
-    # - uses io_method=io_uring
-    # - Uses meson feature autodetection
-    - name: Linux - Debian Trixie - Meson
-
-      env:
-        CCACHE_MAXSIZE: "400M" # tests two different builds
-        SANITIZER_FLAGS: -fsanitize=alignment,undefined
-        PG_TEST_INITDB_EXTRA_OPTS: >-
-          -c io_method=io_uring
-
-      configure_script: |
-        su postgres <<-EOF
-          set -e
-          meson setup \
-            ${MESON_COMMON_PG_CONFIG_ARGS} \
-            --buildtype=debug \
-            ${LINUX_MESON_FEATURES} -Dllvm=enabled \
-            build
-        EOF
-
-      # Also build & test in a 32bit build - it's gotten rare to test that
-      # locally.
-      configure_32_script: |
-        su postgres <<-EOF
-          set -e
-          export CC='ccache gcc -m32'
-          export CXX='ccache g++ -m32'
-          meson setup \
-            ${MESON_COMMON_PG_CONFIG_ARGS} \
-            --buildtype=debug \
-            --pkg-config-path /usr/lib/i386-linux-gnu/pkgconfig/ \
-            -DPERL=perl5.40-i386-linux-gnu \
-            ${LINUX_MESON_FEATURES} -Dlibnuma=disabled \
-            build-32
-        EOF
-
-      build_script: |
-        su postgres <<-EOF
-          set -e
-          ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET}
-          ninja -C build -t missingdeps
-        EOF
-
-      build_32_script: |
-        su postgres <<-EOF
-          set -e
-          ninja -C build-32 -j${BUILD_JOBS} ${MBUILD_TARGET}
-          ninja -C build -t missingdeps
-        EOF
-
-      upload_caches: ccache
-
-      test_world_script: |
-        su postgres <<-EOF
-          set -e
-          ulimit -c unlimited
-          meson test $MTEST_ARGS --num-processes ${TEST_JOBS}
-        EOF
-        # so that we don't upload 64bit logs if 32bit fails
-        rm -rf build/
-
-      # There's currently no coverage of icu with LANG=C in the buildfarm. We
-      # can easily provide some here by running one of the sets of tests that
-      # way. Newer versions of python insist on changing the LC_CTYPE away
-      # from C, prevent that with PYTHONCOERCECLOCALE.
-      test_world_32_script: |
-        su postgres <<-EOF
-          set -e
-          ulimit -c unlimited
-          PYTHONCOERCECLOCALE=0 LANG=C meson test $MTEST_ARGS -C build-32 --num-processes ${TEST_JOBS}
-        EOF
-
-      on_failure:
-        <<: *on_failure_meson
-
-  on_failure:
-    cores_script: src/tools/ci/cores_backtrace.sh linux /tmp/cores
-
-
-# NB: macOS is by far the most expensive OS to run CI for, therefore no
-# expensive additional checks should be added.
-#
-# SPECIAL:
-# - Enables --clone for pg_upgrade and pg_combinebackup
-task:
-  name: macOS - Sequoia - Meson
-
-  env:
-    CPUS: 4 # always get that much for cirrusci macOS instances
-    BUILD_JOBS: $CPUS
-    # Test performance regresses noticeably when using all cores. 8 seems to
-    # work OK. See
-    # https://postgr.es/m/20220927040208.l3shfcidovpzqxfh%40awork3.anarazel.de
-    TEST_JOBS: 8
-    IMAGE: ghcr.io/cirruslabs/macos-runner:sequoia
-
-    CIRRUS_WORKING_DIR: ${HOME}/pgsql/
-    CCACHE_DIR: ${HOME}/ccache
-    MACPORTS_CACHE: ${HOME}/macports-cache
-
-    MESON_FEATURES: >-
-      -Dbonjour=enabled
-      -Ddtrace=enabled
-      -Dgssapi=enabled
-      -Dlibcurl=enabled
-      -Dnls=enabled
-      -Duuid=e2fs
-
-    MACOS_PACKAGE_LIST: >-
-      ccache
-      icu
-      kerberos5
-      lz4
-      meson
-      openldap
-      openssl
-      p5.34-io-tty
-      p5.34-ipc-run
-      python312
-      tcl
-      zstd
-
-    CC: ccache cc
-    CXX: ccache c++
-    CFLAGS: -Og -ggdb
-    CXXFLAGS: -Og -ggdb
-
-    PG_TEST_PG_UPGRADE_MODE: --clone
-    PG_TEST_PG_COMBINEBACKUP_MODE: --clone
-
-  <<: *macos_task_template
-
-  depends_on: SanityCheck
-  only_if: $CI_MACOS_ENABLED
-
-  sysinfo_script: |
-    id
-    uname -a
-    ulimit -a -H && ulimit -a -S
-    export
-
-  setup_core_files_script:
-    - mkdir ${HOME}/cores
-    - sudo sysctl kern.corefile="${HOME}/cores/core.%P"
-
-  # Use macports, even though homebrew is installed. The installation
-  # of the additional packages we need would take quite a while with
-  # homebrew, even if we cache the downloads. We can't cache all of
-  # homebrew, because it's already large. So we use macports. To cache
-  # the installation we create a .dmg file that we mount if it already
-  # exists.
-  # XXX: The reason for the direct p5.34* references is that we'd need
-  # the large macport tree around to figure out that p5-io-tty is
-  # actually p5.34-io-tty. Using the unversioned name works, but
-  # updates macports every time.
-  macports_cache:
-    folder: ${MACPORTS_CACHE}
-    fingerprint_script: |
-      # Reinstall packages if the OS major version, the list of the packages
-      # to install or the MacPorts install script changes.
-      sw_vers -productVersion | sed 's/\..*//'
-      echo $MACOS_PACKAGE_LIST
-      md5 src/tools/ci/ci_macports_packages.sh
-    reupload_on_changes: true
-  setup_additional_packages_script: |
-    sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST
-    # system python doesn't provide headers
-    sudo /opt/local/bin/port select python3 python312
-    # Make macports install visible for subsequent steps
-    echo PATH=/opt/local/sbin/:/opt/local/bin/:$PATH >> $CIRRUS_ENV
-  upload_caches: macports
-
-  ccache_cache:
-    folder: $CCACHE_DIR
-  configure_script: |
-    export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig/"
-    meson setup \
-      ${MESON_COMMON_PG_CONFIG_ARGS} \
-      --buildtype=debug \
-      -Dextra_include_dirs=/opt/local/include \
-      -Dextra_lib_dirs=/opt/local/lib \
-      ${MESON_COMMON_FEATURES} ${MESON_FEATURES} \
-      build
-
-  build_script: ninja -C build -j${BUILD_JOBS} ${MBUILD_TARGET}
-  upload_caches: ccache
-
-  test_world_script: |
-    ulimit -c unlimited # default is 0
-    ulimit -n 1024 # default is 256, pretty low
-    meson test $MTEST_ARGS --num-processes ${TEST_JOBS}
-
-  on_failure:
-    <<: *on_failure_meson
-    cores_script: src/tools/ci/cores_backtrace.sh macos "${HOME}/cores"
-
-
-WINDOWS_ENVIRONMENT_BASE: &WINDOWS_ENVIRONMENT_BASE
-  env:
-    # Half the allowed per-user CPU cores
-    CPUS: 4
-
-    # The default cirrus working dir is in a directory msbuild complains about
-    CIRRUS_WORKING_DIR: "c:/cirrus"
-    # git's tar doesn't deal with drive letters, see
-    # https://postgr.es/m/b6782dc3-a7b0-ed56-175f-f8f54cb08d67%40dunslane.net
-    TAR: "c:/windows/system32/tar.exe"
-    # Avoids port conflicts between concurrent tap test runs
-    PG_TEST_USE_UNIX_SOCKETS: 1
-    PG_REGRESS_SOCK_DIR: "c:/cirrus/"
-    DISK_SIZE: 50
-    IMAGE_FAMILY: pg-ci-windows-ci
-
-  sysinfo_script: |
-    chcp
-    systeminfo
-    powershell -Command get-psdrive -psprovider filesystem
-    set
-
-
-task:
-  name: Windows - Server 2022, VS 2019 - Meson & ninja
-  << : *WINDOWS_ENVIRONMENT_BASE
-
-  env:
-    TEST_JOBS: 8 # wild guess, data based value welcome
-
-    # Cirrus defaults to SetErrorMode(SEM_NOGPFAULTERRORBOX | ...). That
-    # prevents crash reporting from working unless binaries do SetErrorMode()
-    # themselves. Furthermore, it appears that either python or, more likely,
-    # the C runtime has a bug where SEM_NOGPFAULTERRORBOX can very
-    # occasionally *trigger* a crash on process exit - which is hard to debug,
-    # given that it explicitly prevents crash dumps from working...
-    # 0x8001 is SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX
-    CIRRUS_WINDOWS_ERROR_MODE: 0x8001
-
-    MESON_FEATURES:
-      -Dcpp_args=/std:c++20
-      -Dauto_features=disabled
-      -Dldap=enabled
-      -Dssl=openssl
-      -Dtap_tests=enabled
-      -Dplperl=enabled
-      -Dplpython=enabled
-
-  <<: *windows_task_template
-
-  depends_on: SanityCheck
-  only_if: $CI_WINDOWS_ENABLED
-
-  setup_additional_packages_script: |
-    REM choco install -y --no-progress ...
-
-  setup_hosts_file_script: |
-    echo 127.0.0.1 pg-loadbalancetest >> c:\Windows\System32\Drivers\etc\hosts
-    echo 127.0.0.2 pg-loadbalancetest >> c:\Windows\System32\Drivers\etc\hosts
-    echo 127.0.0.3 pg-loadbalancetest >> c:\Windows\System32\Drivers\etc\hosts
-    type c:\Windows\System32\Drivers\etc\hosts
-
-  configure_script: |
-    vcvarsall x64
-    meson setup --backend ninja %MESON_COMMON_PG_CONFIG_ARGS% --buildtype debug -Db_pch=true -Dextra_lib_dirs=c:\openssl\1.1\lib -Dextra_include_dirs=c:\openssl\1.1\include -DTAR=%TAR% %MESON_FEATURES% build
-
-  build_script: |
-    vcvarsall x64
-    ninja -C build %MBUILD_TARGET%
-    ninja -C build -t missingdeps
-
-  check_world_script: |
-    vcvarsall x64
-    meson test %MTEST_ARGS% --num-processes %TEST_JOBS%
-
-  on_failure:
-    <<: *on_failure_meson
-    crashlog_artifacts:
-      path: "crashlog-*.txt"
-      type: text/plain
-
-
-task:
-  << : *WINDOWS_ENVIRONMENT_BASE
-  name: Windows - Server 2022, MinGW64 - Meson
-
-  # See REPO_CI_AUTOMATIC_TRIGGER_TASKS in .cirrus.star.
-  trigger_type: $CI_TRIGGER_TYPE_MINGW
-
-  depends_on: SanityCheck
-  only_if: $CI_MINGW_ENABLED
-
-  env:
-    TEST_JOBS: 4 # higher concurrency causes occasional failures
-    CCACHE_DIR: C:/msys64/ccache
-    CCACHE_MAXSIZE: "500M"
-    CCACHE_SLOPPINESS: pch_defines,time_macros
-    CCACHE_DEPEND: 1
-    # for some reason mingw plpython cannot find its installation without this
-    PYTHONHOME: C:/msys64/ucrt64
-    # prevents MSYS bash from resetting error mode
-    MSYS: winjitdebug
-    # Start bash in current working directory
-    CHERE_INVOKING: 1
-    BASH: C:\msys64\usr\bin\bash.exe -l
-
-    # Keep -Dnls explicitly disabled, as the number of files it creates causes a
-    # noticeable slowdown.
-    MESON_FEATURES: >-
-      -Dnls=disabled
-
-  <<: *windows_task_template
-
-  ccache_cache:
-    folder: ${CCACHE_DIR}
-
-  setup_additional_packages_script: |
-    REM C:\msys64\usr\bin\pacman.exe -S --noconfirm ...
-
-  mingw_info_script: |
-    %BASH% -c "where gcc"
-    %BASH% -c "gcc --version"
-    %BASH% -c "where perl"
-    %BASH% -c "perl --version"
-
-  configure_script: |
-    %BASH% -c "meson setup %MESON_COMMON_PG_CONFIG_ARGS% -Ddebug=true -Doptimization=g -Db_pch=true %MESON_COMMON_FEATURES% %MESON_FEATURES% -DTAR=%TAR% build"
-
-  build_script: |
-    %BASH% -c "ninja -C build ${MBUILD_TARGET}"
-
-  upload_caches: ccache
-
-  test_world_script: |
-    %BASH% -c "meson test %MTEST_ARGS% --num-processes %TEST_JOBS%"
-
-  on_failure:
-    <<: *on_failure_meson
-    crashlog_artifacts:
-      path: "crashlog-*.txt"
-      type: text/plain
-
-
-task:
-  name: CompilerWarnings
-
-  # To limit unnecessary work only run this once the SanityCheck
-  # succeeds. This is particularly important for this task as we intentionally
-  # use always: to continue after failures.
-  depends_on: SanityCheck
-  only_if: $CI_COMPILERWARNINGS_ENABLED
-
-  env:
-    CPUS: 4
-    BUILD_JOBS: 4
-    IMAGE_FAMILY: pg-ci-trixie
-
-    # Use larger ccache cache, as this task compiles with multiple compilers /
-    # flag combinations
-    CCACHE_MAXSIZE: "1G"
-    CCACHE_DIR: "/tmp/ccache_dir"
-
-    LINUX_CONFIGURE_FEATURES: *LINUX_CONFIGURE_FEATURES
-
-  <<: *linux_task_template
-
-  sysinfo_script: |
-    id
-    uname -a
-    cat /proc/cmdline
-    ulimit -a -H && ulimit -a -S
-    gcc -v
-    clang -v
-    export
-
-  ccache_cache:
-    folder: $CCACHE_DIR
-
-  setup_additional_packages_script: |
-    #apt-get update
-    #DEBIAN_FRONTEND=noninteractive apt-get -y install ...
-
-  ###
-  # Test that code can be built with gcc/clang without warnings
-  ###
-
-  setup_script: echo "COPT=-Werror" > src/Makefile.custom
-
-  # Trace probes have a history of getting accidentally broken. Use the
-  # different compilers to build with different combinations of dtrace on/off
-  # and cassert on/off.
-
-  # gcc, cassert off, dtrace on
-  always:
-    gcc_warning_script: |
-      time ./configure \
-        --cache gcc.cache \
-        --enable-dtrace \
-        ${LINUX_CONFIGURE_FEATURES} \
-        CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang"
-      make -s -j${BUILD_JOBS} clean
-      time make -s -j${BUILD_JOBS} world-bin
-
-  # gcc, cassert on, dtrace off
-  always:
-    gcc_a_warning_script: |
-      time ./configure \
-        --cache gcc.cache \
-        --enable-cassert \
-        ${LINUX_CONFIGURE_FEATURES} \
-        CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang"
-      make -s -j${BUILD_JOBS} clean
-      time make -s -j${BUILD_JOBS} world-bin
-
-  # clang, cassert off, dtrace off
-  always:
-    clang_warning_script: |
-      time ./configure \
-        --cache clang.cache \
-        ${LINUX_CONFIGURE_FEATURES} \
-        CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang"
-      make -s -j${BUILD_JOBS} clean
-      time make -s -j${BUILD_JOBS} world-bin
-
-  # clang, cassert on, dtrace on
-  always:
-    clang_a_warning_script: |
-      time ./configure \
-        --cache clang.cache \
-        --enable-cassert \
-        --enable-dtrace \
-        ${LINUX_CONFIGURE_FEATURES} \
-        CC="ccache clang" CXX="ccache clang++" CLANG="ccache clang"
-      make -s -j${BUILD_JOBS} clean
-      time make -s -j${BUILD_JOBS} world-bin
-
-  # cross-compile to windows
-  always:
-    mingw_cross_warning_script: |
-      time ./configure \
-        --host=x86_64-w64-mingw32ucrt \
-        --enable-cassert \
-        --without-icu \
-        CC="ccache x86_64-w64-mingw32ucrt-gcc" \
-        CXX="ccache x86_64-w64-mingw32ucrt-g++"
-      make -s -j${BUILD_JOBS} clean
-      time make -s -j${BUILD_JOBS} world-bin
-
-  ###
-  # Verify docs can be built
-  ###
-  # XXX: Only do this if there have been changes in doc/ since last build
-  always:
-    docs_build_script: |
-      time ./configure \
-        --cache gcc.cache \
-        CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang"
-      make -s -j${BUILD_JOBS} clean
-      time make -s -j${BUILD_JOBS} -C doc
-
-  ###
-  # Verify headerscheck / cpluspluscheck succeed
-  #
-  # - Run both in same script to increase parallelism, use -k to get result of both
-  # - Use -fmax-errors, as particularly cpluspluscheck can be very verbose
-  ###
-  always:
-    headers_headerscheck_script: |
-      time ./configure \
-        ${LINUX_CONFIGURE_FEATURES} \
-        --cache gcc.cache \
-        --quiet \
-        CC="ccache gcc" CXX="ccache g++" CLANG="ccache clang"
-      make -s -j${BUILD_JOBS} clean
-      time make -s -j${BUILD_JOBS} -k ${CHECKFLAGS} headerscheck cpluspluscheck EXTRAFLAGS='-fmax-errors=10'
-
-  always:
-    upload_caches: ccache
diff --git a/src/tools/ci/ci_macports_packages.sh b/src/tools/ci/ci_macports_packages.sh
index c7c4a1c0c60..304b9b43fd4 100755
--- a/src/tools/ci/ci_macports_packages.sh
+++ b/src/tools/ci/ci_macports_packages.sh
@@ -6,7 +6,7 @@
 # when packages are installed or removed.  Any package this script is
 # not instructed to install, will be removed again.
 #
-# This currently expects to be run in a macos cirrus-ci environment.
+# This currently expects to be run in a macos github actions environment.
 
 set -e
 # set -x
@@ -38,8 +38,8 @@ fi
 
 cache_dmg="macports.hfs.dmg"
 
-if [ "$CIRRUS_CI" != "true" ] && [ "$GITHUB_ACTIONS" != "true" ]; then
-    echo "expect to be called within cirrus-ci or github actions" 1>&2
+if [ "$GITHUB_ACTIONS" != "true" ]; then
+    echo "expect to be called within github actions" 1>&2
     exit 1
 fi
 
diff --git a/src/tools/ci/gcp_ram_disk.sh b/src/tools/ci/gcp_ram_disk.sh
deleted file mode 100755
index 18dbb2037f5..00000000000
--- a/src/tools/ci/gcp_ram_disk.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-# Move working directory into a RAM disk for better performance.
-
-set -e
-set -x
-
-mv $CIRRUS_WORKING_DIR $CIRRUS_WORKING_DIR.orig
-mkdir $CIRRUS_WORKING_DIR
-
-case "`uname`" in
-  FreeBSD|NetBSD)
-    mount -t tmpfs tmpfs $CIRRUS_WORKING_DIR
-    ;;
-  OpenBSD)
-    umount /dev/sd0j # unused /usr/obj partition
-    printf "m j\n\n\nswap\nw\nq\n" | disklabel -E sd0
-    swapon /dev/sd0j
-    # Remove the per-process data segment limit so that mount_mfs can allocate
-    # large memory filesystems. Without this, mount_mfs mmap() may fail with
-    # "Cannot allocate memory" if the requested size exceeds the current
-    # datasize limit.
-    ulimit -d unlimited
-    mount -t mfs -o rw,noatime,nodev,-s=10000000 swap $CIRRUS_WORKING_DIR
-    ;;
-esac
-
-cp -a $CIRRUS_WORKING_DIR.orig/. $CIRRUS_WORKING_DIR/
-- 
2.54.0.380.gc69baaf57b


--lyfxwjjve3vodszg
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
	filename="v9a-0004-ci-Store-build-meson-logs-and-name-id-os-task.patch"



^ permalink  raw  reply  [nested|flat] 114+ messages in thread


end of thread, other threads:[~2026-05-28 17:31 UTC | newest]

Thread overview: 114+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2018-11-13 20:58 [PATCH v14 6/7] Restructure TupleTableSlot to allow tuples other than HeapTuple Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-02-07 19:04 [PATCH v2 1/4] Make stack depth check work with asan's use-after-return Andres Freund <[email protected]>
2026-05-28 17:31 [PATCH v9a 03/22] ci: Remove support for cirrus-ci based CI Andres Freund <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox