Re: Undefined behavior detected by new clang's ubsan

Michael Paquier <michael@paquier.xyz>

From: Michael Paquier <michael@paquier.xyz>
To: John Naylor <johncnaylorls@gmail.com>
Cc: Tom Lane <tgl@sss.pgh.pa.us>, Alexander Lakhin <exclusion@gmail.com>, pgsql-hackers <pgsql-hackers@postgresql.org>
Date: 2026-02-04T11:37:24Z
Lists: pgsql-hackers
On Wed, Feb 04, 2026 at 06:15:11PM +0700, John Naylor wrote:
> I logged the offending statement and found
> 
> curchunk: 50
> TOAST_MAX_CHUNK_SIZE: 1996
> sliceoffset: 99994
> chcpystrt 194
> 
> The expression for the offset to the pointer:
> 
> (curchunk * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt
> 
> is zero by way of
> 
> (-194) + 194
> 
> ...so the "+ (-194)" must get cast to "+ (size_t) (-194)" causing the
> overflow. So the parentheses are indeed at fault by forcing
> precedence. The entire offset expression is never negative for our
> regression tests (nor should it ever be), so it's kind of pointless to
> cast any subset of this to a signed type. I went ahead and pushed 0001
> to all versions. Thanks Alexander, for the report and the patch!

Ah.  I've seen this one, actually, while playing with the TOAST patch
set for 64-bit values.  The max chunk size varies as this code would
need to switch between two possible sizes, and I've been super puzzled
by the fact that I had to switch the code to use an unsigned integer
for the declaration of my max_chunk_size, and a signed integer quickly
failed.

Thanks for the fix!
--
Michael

Commits

  1. Future-proof sort template against undefined behavior

  2. Fix various instances of undefined behavior