Re: Clang UndefinedBehaviorSanitize (Postgres14) Detected undefined-behavior

From: Ranier Vilela <ranier(dot)vf(at)gmail(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Peter Geoghegan <pg(at)bowt(dot)ie>, Noah Misch <noah(at)leadboat(dot)com>, Alvaro Herrera <alvherre(at)2ndquadrant(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Clang UndefinedBehaviorSanitize (Postgres14) Detected undefined-behavior
Date: 2020-08-31 16:02:41
Message-ID: CAEudQApePVLtt2HQdcTL9zqt9u20q5F_k322K-vAphFj2M5BZw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

More troubles with undefined-behavior.

This type of code can leaves overflow:
var = (cast) (expression);
diff = (int32) (id1 - id2);

See:
diff64 = ((long int) d1 - (long int) d2);
diff64=-4294901760

#include <stdio.h>
#include <stdint.h>

int main()
{
unsigned int d1 = 3;
unsigned int d2 = 4294901763;
unsigned int diffu32 = 0;
unsigned long int diffu64 = 0;
unsigned long int diff64 = 0;
int32_t diff = 0;

diff = (int32_t) (d1 - d2);
diff64 = ((long int) d1 - (long int) d2);
diffu32 = (unsigned int) (d1 - d2);
diffu64 = (unsigned long int) (d1 - d2);
printf("d1=%u\n", d1);
printf("d2=%u\n", d2);
printf("diff=%d\n", diff);
printf("diffu32=%u\n", diffu32);
printf("diff64=%ld\n", diff64);
printf("diffu64=%lu\n", diffu64);

return 0;
}

output:
d1=3
d2=4294901763
diff=65536
diffu32=65536
diff64=-4294901760
diffu64=65536

(With Ubuntu 64 bits + clang 10)
transam.c:311:22: runtime error: unsigned integer overflow: 3 - 4294901763
cannot be represented in type 'unsigned int'
TransactionIdPrecedes(TransactionId id1, TransactionId id2)
{
/*
* If either ID is a permanent XID then we can just do unsigned
* comparison. If both are normal, do a modulo-2^32 comparison.
*/
int32 diff;

if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
return (id1 < id2);

diff = (int32) (id1 - id2);
return (diff < 0);
}

This works, all time or really with bad numbers can break?
I would like to know, why doesn't it work?

With Windows 10 (64 bits) + msvc 2019 (64 bits)
bool
TransactionIdPrecedes(TransactionId id1, TransactionId id2)
{
/*
* If either ID is a permanent XID then we can just do unsigned
* comparison. If both are normal, do a modulo-2^32 comparison.
*/
int32 diff;
int64 diff64;

if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
return (id1 < id2);

diff = (int32) (id1 - id2);
diff64 = ((int64) id1 - (int64) id2);
fprintf(stderr, "id1=%lu\n", id1);
fprintf(stderr, "id2=%lu\n", id1);
fprintf(stderr, "diff32=%ld\n", diff);
fprintf(stderr, "diff64=%lld\n", diff64);
return (diff64 < 0);
}

id1=498
id2=498
diff32=200000000
diff64=-4094967296
2020-08-31 12:46:30.422 -03 [8908] WARNING: oldest xmin is far in the past
2020-08-31 12:46:30.422 -03 [8908] HINT: Close open transactions soon to
avoid wraparound problems.
You might also need to commit or roll back old prepared transactions, or
drop stale replication slots.

id1=4
id2=4
diff32=-494
diff64=-494

id1=4
id2=4
diff32=50000000
diff64=-4244967296
2020-08-31 12:46:30.423 -03 [8908] FATAL: found xmin 4 from before
relfrozenxid 4244967300
2020-08-31 12:46:30.423 -03 [8908] CONTEXT: while scanning block 0 and
offset 1 of relation "pg_catalog.pg_depend"
2020-08-31 12:46:30.423 -03 [8908] STATEMENT: VACUUM FREEZE;

Most of the time:
id1=498
id2=498
diff32=0
diff64=0
id1=498
id2=498
diff32=0
diff64=0

regards,
Ranier Vilela

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Matthieu Garrigues 2020-08-31 16:05:47 Re: PATCH: Batch/pipelining support for libpq
Previous Message Tom Lane 2020-08-31 15:41:46 Re: Get rid of runtime handling of AlternativeSubPlan?