Re: Undefined behavior detected by new clang's ubsan

From: John Naylor <johncnaylorls(at)gmail(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Alexander Lakhin <exclusion(at)gmail(dot)com>, pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Undefined behavior detected by new clang's ubsan
Date: 2026-01-21 10:05:42
Message-ID: CANWCAZZLjknosPdfZHsQmb_Et8kRZQFsp1gjfr+6=2o9Xsh6qA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Wed, Jan 21, 2026 at 1:52 AM Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:
>
> John Naylor <johncnaylorls(at)gmail(dot)com> writes:
> > I don't think it's great to pass a NULL pointer to a sort, but the
> > length could conceivably be zero for future degenerate cases, so we
> > could silence the warning by adding "if (n < 2) return;" before the
> > for-loop. The advantage of doing that anyway is it allows us to remove
> > all four of the "if (d_ > ST_POINTER_STEP)" branches in the recursion
> > part. That's better for readability.
>
> +1

Okay, I've written that approach. Since it requires a bit more
explanation, I've kept it separate for now.

> With the attached patch applied, `make check-world` passes for me.

As for the rest of the proposed fixes, most seem okay, but I have some nits:

trgm_gist.c:
- TRGM *cachedVal = (TRGM *) (cache + MAXALIGN(siglen));
+ TRGM *cachedVal = cache ? ((TRGM *) (cache + MAXALIGN(siglen))) : NULL;

This is getting a bit unwieldy for a declaration. How about this?

char *cache = (char *) fcinfo->flinfo->fn_extra;
- TRGM *cachedVal = (TRGM *) (cache + MAXALIGN(siglen));
+ TRGM *cachedVal = NULL;
[...]
+ if (cache != NULL)
+ cachedVal = (TRGM *) (cache + MAXALIGN(siglen));

heaptoast.c
memcpy(VARDATA(result) +
- (curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt,
+ (int)(curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt,

Not sure about this one. It would be better if we reversing the
operands allowed us to avoid overflow in the first place:

- (curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt,
+ chcpystrt + (curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset)

Does that silence the warning?

sharedtuplestore.c
- if (accessor->write_pointer + size > accessor->write_end)
+ if ((accessor->write_pointer == NULL && accessor->write_end == NULL
&& size > 0) || (accessor->write_pointer + size >
accessor->write_end))
{
if (accessor->write_chunk == NULL)
{
/* First time through. Allocate chunk. */

I don't see why we have to check so many conditions. The last line
above is where write_pointer is set in a new allocation, so it seems
we could just have

if (accessor->write_pointer == NULL ||
accessor->write_pointer + size > accessor->write_end)

Attachment Content-Type Size
v1-0002-Fix-various-cases-of-undefined-behavior.patch text/x-patch 2.4 KB
v1-0001-Silence-clang-ubsan-warning-in-sort-template.patch text/x-patch 2.8 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Jakub Wartak 2026-01-21 10:30:03 Re: Adding basic NUMA awareness
Previous Message VASUKI M 2026-01-21 09:56:31 Re: Optional skipping of unchanged relations during ANALYZE?