From 176dffdf7d2a0ea2615c4e390a2ab7e69d14f90f Mon Sep 17 00:00:00 2001 From: John Naylor Date: Wed, 4 Feb 2026 17:55:49 +0700 Subject: [PATCH] Fix various instances of undefined behavior Mostly this involves checking for NULL pointer before doing operations that add a non-zero offset. The exception is an overflow warning in heap_fetch_toast_slice(). This was caused by unneeded parentheses forcing an expression to be evaluated to a negative integer, which then got cast to size_t. Per clang 21 undefined behavior sanitizer. Backpatch to all supported versions. Co-authored-by: Alexander Lakhin Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/777bd201-6e3a-4da0-a922-4ea9de46a3ee@gmail.com Backpatch-through: 14 --- contrib/pg_trgm/trgm_gist.c | 5 ++++- src/backend/access/heap/heaptoast.c | 2 +- src/backend/utils/adt/multirangetypes.c | 5 +++-- src/backend/utils/sort/sharedtuplestore.c | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/contrib/pg_trgm/trgm_gist.c b/contrib/pg_trgm/trgm_gist.c index 2f0d61985a5..685275a0f9b 100644 --- a/contrib/pg_trgm/trgm_gist.c +++ b/contrib/pg_trgm/trgm_gist.c @@ -701,10 +701,13 @@ gtrgm_penalty(PG_FUNCTION_ARGS) if (ISARRKEY(newval)) { char *cache = (char *) fcinfo->flinfo->fn_extra; - TRGM *cachedVal = (TRGM *) (cache + MAXALIGN(siglen)); + TRGM *cachedVal = NULL; Size newvalsize = VARSIZE(newval); BITVECP sign; + if (cache != NULL) + cachedVal = (TRGM *) (cache + MAXALIGN(siglen)); + /* * Cache the sign data across multiple calls with the same newval. */ diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c index e28fe47a449..6ddf6c6cf9f 100644 --- a/src/backend/access/heap/heaptoast.c +++ b/src/backend/access/heap/heaptoast.c @@ -768,7 +768,7 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize, chcpyend = (sliceoffset + slicelength - 1) % TOAST_MAX_CHUNK_SIZE; memcpy(VARDATA(result) + - (curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt, + curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset + chcpystrt, chunkdata + chcpystrt, (chcpyend - chcpystrt) + 1); diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index b1942387dc5..9548989d782 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -485,8 +485,9 @@ multirange_canonicalize(TypeCacheEntry *rangetyp, int32 input_range_count, int32 output_range_count = 0; /* Sort the ranges so we can find the ones that overlap/meet. */ - qsort_arg(ranges, input_range_count, sizeof(RangeType *), range_compare, - rangetyp); + if (ranges != NULL) + qsort_arg(ranges, input_range_count, sizeof(RangeType *), + range_compare, rangetyp); /* Now merge where possible: */ for (i = 0; i < input_range_count; i++) diff --git a/src/backend/utils/sort/sharedtuplestore.c b/src/backend/utils/sort/sharedtuplestore.c index 8f35a255263..04189f708fa 100644 --- a/src/backend/utils/sort/sharedtuplestore.c +++ b/src/backend/utils/sort/sharedtuplestore.c @@ -323,7 +323,8 @@ sts_puttuple(SharedTuplestoreAccessor *accessor, void *meta_data, /* Do we have space? */ size = accessor->sts->meta_data_size + tuple->t_len; - if (accessor->write_pointer + size > accessor->write_end) + if (accessor->write_pointer == NULL || + accessor->write_pointer + size > accessor->write_end) { if (accessor->write_chunk == NULL) {