1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-19 13:42:17 +03:00

Remove dependence on -fwrapv semantics in a few places.

This commit attempts to update a few places, such as the money,
numeric, and timestamp types, to no longer rely on signed integer
wrapping for correctness.  This is intended to move us closer
towards removing -fwrapv, which may enable some compiler
optimizations.  However, there is presently no plan to actually
remove that compiler option in the near future.

Besides using some of the existing overflow-aware routines in
int.h, this commit introduces and makes use of some new ones.
Specifically, it adds functions that accept a signed integer and
return its absolute value as an unsigned integer with the same
width (e.g., pg_abs_s64()).  It also adds functions that accept an
unsigned integer, store the result of negating that integer in a
signed integer with the same width, and return whether the negation
overflowed (e.g., pg_neg_u64_overflow()).

Finally, this commit adds a couple of tests for timestamps near
POSTGRES_EPOCH_JDATE.

Author: Joseph Koshakow
Reviewed-by: Tom Lane, Heikki Linnakangas, Jian He
Discussion: https://postgr.es/m/CAAvxfHdBPOyEGS7s%2Bxf4iaW0-cgiq25jpYdWBqQqvLtLe_t6tw%40mail.gmail.com
This commit is contained in:
Nathan Bossart
2024-08-15 15:47:31 -05:00
parent ad89d71978
commit 9e9a2b7031
10 changed files with 189 additions and 65 deletions

View File

@@ -18,6 +18,7 @@
#include <limits.h>
#include <ctype.h>
#include "common/int.h"
#include "port/pg_bitutils.h"
#include "utils/builtins.h"
@@ -131,6 +132,7 @@ pg_strtoint16_safe(const char *s, Node *escontext)
uint16 tmp = 0;
bool neg = false;
unsigned char digit;
int16 result;
/*
* The majority of cases are likely to be base-10 digits without any
@@ -190,10 +192,9 @@ pg_strtoint16_safe(const char *s, Node *escontext)
if (neg)
{
/* check the negative equivalent will fit without overflowing */
if (unlikely(tmp > (uint16) (-(PG_INT16_MIN + 1)) + 1))
if (unlikely(pg_neg_u16_overflow(tmp, &result)))
goto out_of_range;
return -((int16) tmp);
return result;
}
if (unlikely(tmp > PG_INT16_MAX))
@@ -333,10 +334,9 @@ slow:
if (neg)
{
/* check the negative equivalent will fit without overflowing */
if (tmp > (uint16) (-(PG_INT16_MIN + 1)) + 1)
if (unlikely(pg_neg_u16_overflow(tmp, &result)))
goto out_of_range;
return -((int16) tmp);
return result;
}
if (tmp > PG_INT16_MAX)
@@ -393,6 +393,7 @@ pg_strtoint32_safe(const char *s, Node *escontext)
uint32 tmp = 0;
bool neg = false;
unsigned char digit;
int32 result;
/*
* The majority of cases are likely to be base-10 digits without any
@@ -452,10 +453,9 @@ pg_strtoint32_safe(const char *s, Node *escontext)
if (neg)
{
/* check the negative equivalent will fit without overflowing */
if (unlikely(tmp > (uint32) (-(PG_INT32_MIN + 1)) + 1))
if (unlikely(pg_neg_u32_overflow(tmp, &result)))
goto out_of_range;
return -((int32) tmp);
return result;
}
if (unlikely(tmp > PG_INT32_MAX))
@@ -595,10 +595,9 @@ slow:
if (neg)
{
/* check the negative equivalent will fit without overflowing */
if (tmp > (uint32) (-(PG_INT32_MIN + 1)) + 1)
if (unlikely(pg_neg_u32_overflow(tmp, &result)))
goto out_of_range;
return -((int32) tmp);
return result;
}
if (tmp > PG_INT32_MAX)
@@ -655,6 +654,7 @@ pg_strtoint64_safe(const char *s, Node *escontext)
uint64 tmp = 0;
bool neg = false;
unsigned char digit;
int64 result;
/*
* The majority of cases are likely to be base-10 digits without any
@@ -714,10 +714,9 @@ pg_strtoint64_safe(const char *s, Node *escontext)
if (neg)
{
/* check the negative equivalent will fit without overflowing */
if (unlikely(tmp > (uint64) (-(PG_INT64_MIN + 1)) + 1))
if (unlikely(pg_neg_u64_overflow(tmp, &result)))
goto out_of_range;
return -((int64) tmp);
return result;
}
if (unlikely(tmp > PG_INT64_MAX))
@@ -857,10 +856,9 @@ slow:
if (neg)
{
/* check the negative equivalent will fit without overflowing */
if (tmp > (uint64) (-(PG_INT64_MIN + 1)) + 1)
if (unlikely(pg_neg_u64_overflow(tmp, &result)))
goto out_of_range;
return -((int64) tmp);
return result;
}
if (tmp > PG_INT64_MAX)