Re: Clang UndefinedBehaviorSanitize (Postgres14) Detected undefined-behavior - Mailing list pgsql-hackers

From Ranier Vilela
Subject Re: Clang UndefinedBehaviorSanitize (Postgres14) Detected undefined-behavior
Date
Msg-id CAEudQApePVLtt2HQdcTL9zqt9u20q5F_k322K-vAphFj2M5BZw@mail.gmail.com
Whole thread Raw
In response to Re: Clang UndefinedBehaviorSanitize (Postgres14) Detected undefined-behavior  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Clang UndefinedBehaviorSanitize (Postgres14) Detected undefined-behavior
List 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

pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: Get rid of runtime handling of AlternativeSubPlan?
Next
From: Matthieu Garrigues
Date:
Subject: Re: PATCH: Batch/pipelining support for libpq