agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH v14 6/7] Restructure TupleTableSlot to allow tuples other than HeapTuple 114+ messages / 2 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 v4 1/4] pg_dump/pg_dumpall: bump minimum supported version to v10 @ 2026-04-17 17:15 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 114+ messages in thread From: Nathan Bossart @ 2026-04-17 17:15 UTC (permalink / raw) --- doc/src/sgml/ref/pg_dump.sgml | 14 +- doc/src/sgml/runtime.sgml | 2 +- src/bin/pg_dump/pg_dump.c | 330 ++-------------------------------- src/bin/pg_dump/pg_dumpall.c | 32 +--- 4 files changed, 22 insertions(+), 356 deletions(-) diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index ae1bc14d2f2..64a3447e445 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -407,18 +407,6 @@ PostgreSQL documentation and there is no way to continue with the dump, so <application>pg_dump</application> has no choice but to abort the dump. </para> - <para> - To perform a parallel dump, the database server needs to support - synchronized snapshots, a feature that was introduced in - <productname>PostgreSQL</productname> 9.2 for primary servers and 10 - for standbys. With this feature, database clients can ensure they see - the same data set even though they use different connections. - <command>pg_dump -j</command> uses multiple database connections; it - connects to the database once with the leader process and once again - for each worker job. Without the synchronized snapshot feature, the - different worker jobs wouldn't be guaranteed to see the same data in - each connection, which could lead to an inconsistent backup. - </para> </listitem> </varlistentry> @@ -1718,7 +1706,7 @@ CREATE DATABASE foo WITH TEMPLATE template0; <productname>PostgreSQL</productname> server versions newer than <application>pg_dump</application>'s version. <application>pg_dump</application> can also dump from <productname>PostgreSQL</productname> servers older than its own version. - (Currently, servers back to version 9.2 are supported.) + (Currently, servers back to version 10 are supported.) However, <application>pg_dump</application> cannot dump from <productname>PostgreSQL</productname> servers newer than its own major version; it will refuse to even try, rather than risk making an invalid dump. diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index dfa292c2c3a..d9984910cc4 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1776,7 +1776,7 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput version of <productname>PostgreSQL</productname>, to take advantage of enhancements that might have been made in these programs. Current releases of the - dump programs can read data from any server version back to 9.2. + dump programs can read data from any server version back to 10. </para> <para> diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index a0f7f8e2168..75c27a08540 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -977,10 +977,10 @@ main(int argc, char **argv) /* - * We allow the server to be back to 9.2, and up to any minor release of + * We allow the server to be back to 10, and up to any minor release of * our own major version. (See also version check in pg_dumpall.c.) */ - fout->minRemoteVersion = 90200; + fout->minRemoteVersion = 100000; fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99; fout->numWorkers = numWorkers; @@ -1491,9 +1491,7 @@ setup_connection(Archive *AH, const char *dumpencoding, * Disable timeouts if supported. */ ExecuteSqlStatement(AH, "SET statement_timeout = 0"); - if (AH->remoteVersion >= 90300) ExecuteSqlStatement(AH, "SET lock_timeout = 0"); - if (AH->remoteVersion >= 90600) ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0"); if (AH->remoteVersion >= 170000) ExecuteSqlStatement(AH, "SET transaction_timeout = 0"); @@ -1507,13 +1505,10 @@ setup_connection(Archive *AH, const char *dumpencoding, /* * Adjust row-security mode, if supported. */ - if (AH->remoteVersion >= 90500) - { if (dopt->enable_row_security) ExecuteSqlStatement(AH, "SET row_security = on"); else ExecuteSqlStatement(AH, "SET row_security = off"); - } /* * For security reasons, we restrict the expansion of non-system views and @@ -1568,11 +1563,7 @@ setup_connection(Archive *AH, const char *dumpencoding, destroyPQExpBuffer(query); } else if (AH->numWorkers > 1) - { - if (AH->isStandby && AH->remoteVersion < 100000) - pg_fatal("parallel dumps from standby servers are not supported by this server version"); AH->sync_snapshot_id = get_synchronized_snapshot(AH); - } } /* Set up connection for a parallel worker process */ @@ -1964,12 +1955,7 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout) if (fout->dopt->binary_upgrade) dobj->dump = ext->dobj.dump; else - { - if (fout->remoteVersion < 90600) - dobj->dump = DUMP_COMPONENT_NONE; - else dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL); - } return true; } @@ -2000,11 +1986,10 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout) simple_oid_list_member(&schema_include_oids, nsinfo->dobj.catId.oid) ? DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE; - else if (fout->remoteVersion >= 90600 && - strcmp(nsinfo->dobj.name, "pg_catalog") == 0) + else if (strcmp(nsinfo->dobj.name, "pg_catalog") == 0) { /* - * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if + * We dump out any ACLs defined in pg_catalog, if * they are interesting (and not the original ACLs which were set at * initdb time, see pg_init_privs). */ @@ -2213,8 +2198,7 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout) else { if (plang->dobj.catId.oid <= g_last_builtin_oid) - plang->dobj.dump = fout->remoteVersion < 90600 ? - DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL; + plang->dobj.dump = DUMP_COMPONENT_ACL; else plang->dobj.dump = DUMP_COMPONENT_ALL; } @@ -2231,13 +2215,6 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout) static void selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout) { - /* see getAccessMethods() comment about v9.6. */ - if (fout->remoteVersion < 90600) - { - method->dobj.dump = DUMP_COMPONENT_NONE; - return; - } - if (checkExtensionMembership(&method->dobj, fout)) return; /* extension membership overrides all else */ @@ -3123,10 +3100,6 @@ buildMatViewRefreshDependencies(Archive *fout) i_objid, i_refobjid; - /* No Mat Views before 9.3. */ - if (fout->remoteVersion < 90300) - return; - query = createPQExpBuffer(); appendPQExpBufferStr(query, "WITH RECURSIVE w AS " @@ -3325,10 +3298,7 @@ dumpDatabase(Archive *fout) "datcollate, datctype, datfrozenxid, " "datacl, acldefault('d', datdba) AS acldefault, " "datistemplate, datconnlimit, "); - if (fout->remoteVersion >= 90300) appendPQExpBufferStr(dbQry, "datminmxid, "); - else - appendPQExpBufferStr(dbQry, "0 AS datminmxid, "); if (fout->remoteVersion >= 170000) appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, "); else if (fout->remoteVersion >= 150000) @@ -3670,17 +3640,11 @@ dumpDatabase(Archive *fout) ii_oid, ii_relminmxid; - if (fout->remoteVersion >= 90300) appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n" "FROM pg_catalog.pg_class\n" "WHERE oid IN (%u, %u, %u, %u);\n", LargeObjectRelationId, LargeObjectLOidPNIndexId, LargeObjectMetadataRelationId, LargeObjectMetadataOidIndexId); - else - appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n" - "FROM pg_catalog.pg_class\n" - "WHERE oid IN (%u, %u);\n", - LargeObjectRelationId, LargeObjectLOidPNIndexId); lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK); @@ -4243,10 +4207,6 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) j, ntups; - /* No policies before 9.5 */ - if (fout->remoteVersion < 90500) - return; - /* Skip if --no-policies was specified */ if (dopt->no_policies) return; @@ -4316,10 +4276,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) printfPQExpBuffer(query, "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, "); - if (fout->remoteVersion >= 100000) appendPQExpBufferStr(query, "pol.polpermissive, "); - else - appendPQExpBufferStr(query, "'t' as polpermissive, "); appendPQExpBuffer(query, "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE " " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, " @@ -4534,7 +4491,7 @@ getPublications(Archive *fout) int i, ntups; - if (dopt->no_publications || fout->remoteVersion < 100000) + if (dopt->no_publications) return; query = createPQExpBuffer(); @@ -4897,7 +4854,7 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables) j, ntups; - if (dopt->no_publications || fout->remoteVersion < 100000) + if (dopt->no_publications) return; query = createPQExpBuffer(); @@ -5187,7 +5144,7 @@ getSubscriptions(Archive *fout) int i, ntups; - if (dopt->no_subscriptions || fout->remoteVersion < 100000) + if (dopt->no_subscriptions) return; if (!is_superuser(fout)) @@ -6675,24 +6632,12 @@ getAccessMethods(Archive *fout) query = createPQExpBuffer(); /* - * Select all access methods from pg_am table. v9.6 introduced CREATE - * ACCESS METHOD, so earlier versions usually have only built-in access - * methods. v9.6 also changed the access method API, replacing dozens of - * pg_am columns with amhandler. Even if a user created an access method - * by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am - * columns to a v9.6+ CREATE ACCESS METHOD. Hence, before v9.6, read - * pg_am just to facilitate findAccessMethodByOid() providing the - * OID-to-name mapping. + * Select all access methods from pg_am table. */ appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, "); - if (fout->remoteVersion >= 90600) appendPQExpBufferStr(query, "amtype, " "amhandler::pg_catalog.regproc AS amhandler "); - else - appendPQExpBufferStr(query, - "'i'::pg_catalog.\"char\" AS amtype, " - "'-'::pg_catalog.regproc AS amhandler "); appendPQExpBufferStr(query, "FROM pg_am"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -6878,15 +6823,12 @@ getAggregates(Archive *fout) int i_proowner; int i_aggacl; int i_acldefault; + const char *agg_check; /* * Find all interesting aggregates. See comment in getFuncs() for the * rationale behind the filtering logic. */ - if (fout->remoteVersion >= 90600) - { - const char *agg_check; - agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'" : "p.proisagg"); @@ -6916,29 +6858,6 @@ getAggregates(Archive *fout) "refclassid = 'pg_extension'::regclass AND " "deptype = 'e')"); appendPQExpBufferChar(query, ')'); - } - else - { - appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, " - "pronamespace AS aggnamespace, " - "pronargs, proargtypes, " - "proowner, " - "proacl AS aggacl, " - "acldefault('f', proowner) AS acldefault " - "FROM pg_proc p " - "WHERE proisagg AND (" - "pronamespace != " - "(SELECT oid FROM pg_namespace " - "WHERE nspname = 'pg_catalog')"); - if (dopt->binary_upgrade) - appendPQExpBufferStr(query, - " OR EXISTS(SELECT 1 FROM pg_depend WHERE " - "classid = 'pg_proc'::regclass AND " - "objid = p.oid AND " - "refclassid = 'pg_extension'::regclass AND " - "deptype = 'e')"); - appendPQExpBufferChar(query, ')'); - } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -7021,6 +6940,7 @@ getFuncs(Archive *fout) int i_prorettype; int i_proacl; int i_acldefault; + const char *not_agg_check; /* * Find all interesting functions. This is a bit complicated: @@ -7039,14 +6959,10 @@ getFuncs(Archive *fout) * include them, since we want to dump extension members individually in * that mode. Also, if they are used by casts or transforms then we need * to gather the information about them, though they won't be dumped if - * they are built-in. Also, in 9.6 and up, include functions in + * they are built-in. Also, include functions in * pg_catalog if they have an ACL different from what's shown in * pg_init_privs (so we have to join to pg_init_privs; annoying). */ - if (fout->remoteVersion >= 90600) - { - const char *not_agg_check; - not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'" : "NOT p.proisagg"); @@ -7090,46 +7006,6 @@ getFuncs(Archive *fout) appendPQExpBufferStr(query, "\n OR p.proacl IS DISTINCT FROM pip.initprivs"); appendPQExpBufferChar(query, ')'); - } - else - { - appendPQExpBuffer(query, - "SELECT tableoid, oid, proname, prolang, " - "pronargs, proargtypes, prorettype, proacl, " - "acldefault('f', proowner) AS acldefault, " - "pronamespace, " - "proowner " - "FROM pg_proc p " - "WHERE NOT proisagg" - "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " - "WHERE classid = 'pg_proc'::regclass AND " - "objid = p.oid AND deptype = 'i')" - "\n AND (" - "\n pronamespace != " - "(SELECT oid FROM pg_namespace " - "WHERE nspname = 'pg_catalog')" - "\n OR EXISTS (SELECT 1 FROM pg_cast" - "\n WHERE pg_cast.oid > '%u'::oid" - "\n AND p.oid = pg_cast.castfunc)", - g_last_builtin_oid); - - if (fout->remoteVersion >= 90500) - appendPQExpBuffer(query, - "\n OR EXISTS (SELECT 1 FROM pg_transform" - "\n WHERE pg_transform.oid > '%u'::oid" - "\n AND (p.oid = pg_transform.trffromsql" - "\n OR p.oid = pg_transform.trftosql))", - g_last_builtin_oid); - - if (dopt->binary_upgrade) - appendPQExpBufferStr(query, - "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE " - "classid = 'pg_proc'::regclass AND " - "objid = p.oid AND " - "refclassid = 'pg_extension'::regclass AND " - "deptype = 'e')"); - appendPQExpBufferChar(query, ')'); - } res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -7378,64 +7254,31 @@ getTables(Archive *fout, int *numTables) appendPQExpBufferStr(query, "c.relhasoids, "); - if (fout->remoteVersion >= 90300) appendPQExpBufferStr(query, "c.relispopulated, "); - else - appendPQExpBufferStr(query, - "'t' as relispopulated, "); - if (fout->remoteVersion >= 90400) appendPQExpBufferStr(query, "c.relreplident, "); - else - appendPQExpBufferStr(query, - "'d' AS relreplident, "); - if (fout->remoteVersion >= 90500) appendPQExpBufferStr(query, "c.relrowsecurity, c.relforcerowsecurity, "); - else - appendPQExpBufferStr(query, - "false AS relrowsecurity, " - "false AS relforcerowsecurity, "); - if (fout->remoteVersion >= 90300) appendPQExpBufferStr(query, "c.relminmxid, tc.relminmxid AS tminmxid, "); - else - appendPQExpBufferStr(query, - "0 AS relminmxid, 0 AS tminmxid, "); - if (fout->remoteVersion >= 90300) appendPQExpBufferStr(query, "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, " "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text " "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "); - else - appendPQExpBufferStr(query, - "c.reloptions, NULL AS checkoption, "); - if (fout->remoteVersion >= 90600) appendPQExpBufferStr(query, "am.amname, "); - else - appendPQExpBufferStr(query, - "NULL AS amname, "); - if (fout->remoteVersion >= 90600) appendPQExpBufferStr(query, "(d.deptype = 'i') IS TRUE AS is_identity_sequence, "); - else - appendPQExpBufferStr(query, - "false AS is_identity_sequence, "); - if (fout->remoteVersion >= 100000) appendPQExpBufferStr(query, "c.relispartition AS ispartition "); - else - appendPQExpBufferStr(query, - "false AS ispartition "); /* * Left join to pg_depend to pick up dependency info linking sequences to @@ -7453,9 +7296,8 @@ getTables(Archive *fout, int *numTables) "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n"); /* - * In 9.6 and up, left join to pg_am to pick up the amname. + * Left join to pg_am to pick up the amname. */ - if (fout->remoteVersion >= 90600) appendPQExpBufferStr(query, "LEFT JOIN pg_am am ON (c.relam = am.oid)\n"); @@ -8028,12 +7870,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) "t.reloptions AS indreloptions, "); - if (fout->remoteVersion >= 90400) appendPQExpBufferStr(query, "i.indisreplident, "); - else - appendPQExpBufferStr(query, - "false AS indisreplident, "); if (fout->remoteVersion >= 110000) appendPQExpBufferStr(query, @@ -8318,10 +8156,6 @@ getExtendedStatistics(Archive *fout) int i_stattarget; int i; - /* Extended statistics were new in v10 */ - if (fout->remoteVersion < 100000) - return; - query = createPQExpBuffer(); if (fout->remoteVersion < 130000) @@ -8988,10 +8822,6 @@ getEventTriggers(Archive *fout) i_evtenabled; int ntups; - /* Before 9.3, there are no event triggers */ - if (fout->remoteVersion < 90300) - return; - query = createPQExpBuffer(); appendPQExpBufferStr(query, @@ -9258,10 +9088,6 @@ getTransforms(Archive *fout) int i_trffromsql; int i_trftosql; - /* Transforms didn't exist pre-9.5 */ - if (fout->remoteVersion < 90500) - return; - query = createPQExpBuffer(); appendPQExpBufferStr(query, "SELECT tableoid, oid, " @@ -9489,12 +9315,8 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables) appendPQExpBufferStr(q, "'' AS attcompression,\n"); - if (fout->remoteVersion >= 100000) appendPQExpBufferStr(q, "a.attidentity,\n"); - else - appendPQExpBufferStr(q, - "'' AS attidentity,\n"); if (fout->remoteVersion >= 110000) appendPQExpBufferStr(q, @@ -10897,8 +10719,6 @@ getAdditionalACLs(Archive *fout) PQclear(res); /* Fetch initial-privileges data */ - if (fout->remoteVersion >= 90600) - { printfPQExpBuffer(query, "SELECT objoid, classoid, objsubid, privtype, initprivs " "FROM pg_init_privs"); @@ -10966,7 +10786,6 @@ getAdditionalACLs(Archive *fout) } } PQclear(res); - } destroyPQExpBuffer(query); } @@ -11141,15 +10960,6 @@ fetchAttributeStats(Archive *fout) static bool restarted; int max_rels = MAX_ATTR_STATS_RELS; - /* - * Our query for retrieving statistics for multiple relations uses WITH - * ORDINALITY and multi-argument UNNEST(), both of which were introduced - * in v9.4. For older versions, we resort to gathering statistics for a - * single relation at a time. - */ - if (fout->remoteVersion < 90400) - max_rels = 1; - /* If we're just starting, set our TOC pointer. */ if (!te) te = AH->toc->next; @@ -11320,16 +11130,11 @@ dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te) * The results must be in the order of the relations supplied in the * parameters to ensure we remain in sync as we walk through the TOC. * - * For v9.4 through v18, the redundant filter clause on s.tablename = + * For versions before 19, the redundant filter clause on s.tablename = * ANY(...) seems sufficient to convince the planner to use * pg_class_relname_nsp_index, which avoids a full scan of pg_stats. * In newer versions, pg_stats returns the table OIDs, eliminating the * need for that hack. - * - * Our query for retrieving statistics for multiple relations uses - * WITH ORDINALITY and multi-argument UNNEST(), both of which were - * introduced in v9.4. For older versions, we resort to gathering - * statistics for a single relation at a time. */ if (fout->remoteVersion >= 190000) appendPQExpBufferStr(query, @@ -11337,7 +11142,7 @@ dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te) "JOIN unnest($1) WITH ORDINALITY AS u (tableid, ord) " "ON s.tableid = u.tableid " "ORDER BY u.ord, s.attname, s.inherited"); - else if (fout->remoteVersion >= 90400) + else appendPQExpBufferStr(query, "FROM pg_catalog.pg_stats s " "JOIN unnest($1, $2) WITH ORDINALITY AS u (schemaname, tablename, ord) " @@ -11345,12 +11150,6 @@ dumpRelationStats_dumper(Archive *fout, const void *userArg, const TocEntry *te) "AND s.tablename = u.tablename " "WHERE s.tablename = ANY($2) " "ORDER BY u.ord, s.attname, s.inherited"); - else - appendPQExpBufferStr(query, - "FROM pg_catalog.pg_stats s " - "WHERE s.schemaname = $1[1] " - "AND s.tablename = $2[1] " - "ORDER BY s.attname, s.inherited"); ExecuteSqlStatement(fout, query->data); @@ -13672,19 +13471,11 @@ dumpFunc(Archive *fout, const FuncInfo *finfo) "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n" "proleakproof,\n"); - if (fout->remoteVersion >= 90500) appendPQExpBufferStr(query, "array_to_string(protrftypes, ' ') AS protrftypes,\n"); - else - appendPQExpBufferStr(query, - "NULL AS protrftypes,\n"); - if (fout->remoteVersion >= 90600) appendPQExpBufferStr(query, "proparallel,\n"); - else - appendPQExpBufferStr(query, - "'u' AS proparallel,\n"); if (fout->remoteVersion >= 110000) appendPQExpBufferStr(query, @@ -15174,14 +14965,9 @@ dumpCollation(Archive *fout, const CollInfo *collinfo) /* Get collation-specific details */ appendPQExpBufferStr(query, "SELECT "); - if (fout->remoteVersion >= 100000) appendPQExpBufferStr(query, "collprovider, " "collversion, "); - else - appendPQExpBufferStr(query, - "'c' AS collprovider, " - "NULL AS collversion, "); if (fout->remoteVersion >= 120000) appendPQExpBufferStr(query, @@ -15588,7 +15374,6 @@ dumpAgg(Archive *fout, const AggInfo *agginfo) "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n" "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"); - if (fout->remoteVersion >= 90400) appendPQExpBufferStr(query, "aggkind,\n" "aggmtransfn,\n" @@ -15600,31 +15385,12 @@ dumpAgg(Archive *fout, const AggInfo *agginfo) "aggtransspace,\n" "aggmtransspace,\n" "aggminitval,\n"); - else - appendPQExpBufferStr(query, - "'n' AS aggkind,\n" - "'-' AS aggmtransfn,\n" - "'-' AS aggminvtransfn,\n" - "'-' AS aggmfinalfn,\n" - "0 AS aggmtranstype,\n" - "false AS aggfinalextra,\n" - "false AS aggmfinalextra,\n" - "0 AS aggtransspace,\n" - "0 AS aggmtransspace,\n" - "NULL AS aggminitval,\n"); - if (fout->remoteVersion >= 90600) appendPQExpBufferStr(query, "aggcombinefn,\n" "aggserialfn,\n" "aggdeserialfn,\n" "proparallel,\n"); - else - appendPQExpBufferStr(query, - "'-' AS aggcombinefn,\n" - "'-' AS aggserialfn,\n" - "'-' AS aggdeserialfn,\n" - "'u' AS proparallel,\n"); if (fout->remoteVersion >= 110000) appendPQExpBufferStr(query, @@ -17084,8 +16850,6 @@ dumpTable(Archive *fout, const TableInfo *tbinfo) appendPQExpBufferStr(query, "PREPARE getColumnACLs(pg_catalog.oid) AS\n"); - if (fout->remoteVersion >= 90600) - { /* * In principle we should call acldefault('c', relowner) to * get the default ACL for a column. However, we don't @@ -17110,17 +16874,6 @@ dumpTable(Archive *fout, const TableInfo *tbinfo) "NOT at.attisdropped " "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) " "ORDER BY at.attnum"); - } - else - { - appendPQExpBufferStr(query, - "SELECT attname, attacl, '{}' AS acldefault, " - "NULL AS privtype, NULL AS initprivs " - "FROM pg_catalog.pg_attribute " - "WHERE attrelid = $1 AND NOT attisdropped " - "AND attacl IS NOT NULL " - "ORDER BY attnum"); - } ExecuteSqlStatement(fout, query->data); @@ -19410,16 +19163,10 @@ collectSequences(Archive *fout) const char *query; /* - * Before Postgres 10, sequence metadata is in the sequence itself. With - * some extra effort, we might be able to use the sorted table for those - * versions, but for now it seems unlikely to be worth it. - * * Since version 18, we can gather the sequence data in this query with * pg_get_sequence_data(), but we only do so for non-schema-only dumps. */ - if (fout->remoteVersion < 100000) - return; - else if (fout->remoteVersion < 180000 || + if (fout->remoteVersion < 180000 || (!fout->dopt->dumpData && !fout->dopt->sequence_data)) query = "SELECT seqrelid, format_type(seqtypid, NULL), " "seqstart, seqincrement, " @@ -19477,59 +19224,20 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo) PQExpBuffer delqry = createPQExpBuffer(); char *qseqname; TableInfo *owning_tab = NULL; + SequenceItem key = {0}; qseqname = pg_strdup(fmtId(tbinfo->dobj.name)); /* - * For versions >= 10, the sequence information is gathered in a sorted + * The sequence information is gathered in a sorted * table before any calls to dumpSequence(). See collectSequences() for * more information. */ - if (fout->remoteVersion >= 100000) - { - SequenceItem key = {0}; - Assert(sequences); key.oid = tbinfo->dobj.catId.oid; seq = bsearch(&key, sequences, nsequences, sizeof(SequenceItem), SequenceItemCmp); - } - else - { - PGresult *res; - - /* - * Before PostgreSQL 10, sequence metadata is in the sequence itself. - * - * Note: it might seem that 'bigint' potentially needs to be - * schema-qualified, but actually that's a keyword. - */ - appendPQExpBuffer(query, - "SELECT 'bigint' AS sequence_type, " - "start_value, increment_by, max_value, min_value, " - "cache_value, is_cycled FROM %s", - fmtQualifiedDumpable(tbinfo)); - - res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); - - if (PQntuples(res) != 1) - pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)", - "query to get data of sequence \"%s\" returned %d rows (expected 1)", - PQntuples(res)), - tbinfo->dobj.name, PQntuples(res)); - - seq = pg_malloc0_object(SequenceItem); - seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0)); - seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10); - seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10); - seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10); - seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10); - seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10); - seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0); - - PQclear(res); - } /* Calculate default limits for a sequence of this type */ is_ascending = (seq->incby >= 0); @@ -19708,8 +19416,6 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo) tbinfo->dobj.namespace->dobj.name, tbinfo->rolname, tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId); - if (fout->remoteVersion < 100000) - pg_free(seq); destroyPQExpBuffer(query); destroyPQExpBuffer(delqry); free(qseqname); diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index c1f43113c53..5b10f7122b7 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -693,11 +693,11 @@ main(int argc, char *argv[]) fout->verbose = verbose; /* - * We allow the server to be back to 9.2, and up to any minor release + * We allow the server to be back to 10, and up to any minor release * of our own major version. (See also version check in * pg_dumpall.c.) */ - fout->minRemoteVersion = 90200; + fout->minRemoteVersion = 100000; fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99; fout->numWorkers = 1; @@ -954,17 +954,11 @@ dropRoles(PGconn *conn) int i_rolname; int i; - if (server_version >= 90600) printfPQExpBuffer(buf, "SELECT rolname " "FROM %s " "WHERE rolname !~ '^pg_' " "ORDER BY 1", role_catalog); - else - printfPQExpBuffer(buf, - "SELECT rolname " - "FROM %s " - "ORDER BY 1", role_catalog); res = executeQuery(conn, buf->data); @@ -1041,7 +1035,6 @@ dumpRoles(PGconn *conn) * Notes: rolconfig is dumped later, and pg_authid must be used for * extracting rolcomment regardless of role_catalog. */ - if (server_version >= 90600) printfPQExpBuffer(buf, "SELECT oid, rolname, rolsuper, rolinherit, " "rolcreaterole, rolcreatedb, " @@ -1052,27 +1045,6 @@ dumpRoles(PGconn *conn) "FROM %s " "WHERE rolname !~ '^pg_' " "ORDER BY 2", role_catalog); - else if (server_version >= 90500) - printfPQExpBuffer(buf, - "SELECT oid, rolname, rolsuper, rolinherit, " - "rolcreaterole, rolcreatedb, " - "rolcanlogin, rolconnlimit, rolpassword, " - "rolvaliduntil, rolreplication, rolbypassrls, " - "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, " - "rolname = current_user AS is_current_user " - "FROM %s " - "ORDER BY 2", role_catalog); - else - printfPQExpBuffer(buf, - "SELECT oid, rolname, rolsuper, rolinherit, " - "rolcreaterole, rolcreatedb, " - "rolcanlogin, rolconnlimit, rolpassword, " - "rolvaliduntil, rolreplication, " - "false as rolbypassrls, " - "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, " - "rolname = current_user AS is_current_user " - "FROM %s " - "ORDER BY 2", role_catalog); res = executeQuery(conn, buf->data); -- 2.50.1 (Apple Git-155) --2xrO7hiVfr8aWtYg Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v4-0002-pg_upgrade-bump-minimum-supported-version-to-v10.patch ^ permalink raw reply [nested|flat] 114+ messages in thread
end of thread, other threads:[~2026-04-17 17:15 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-04-17 17:15 [PATCH v4 1/4] pg_dump/pg_dumpall: bump minimum supported version to v10 Nathan Bossart <[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