Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9e9a2b7

Browse files
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 integerwrapping for correctness. This is intended to move us closertowards removing -fwrapv, which may enable some compileroptimizations. However, there is presently no plan to actuallyremove that compiler option in the near future.Besides using some of the existing overflow-aware routines inint.h, this commit introduces and makes use of some new ones.Specifically, it adds functions that accept a signed integer andreturn its absolute value as an unsigned integer with the samewidth (e.g., pg_abs_s64()). It also adds functions that accept anunsigned integer, store the result of negating that integer in asigned integer with the same width, and return whether the negationoverflowed (e.g., pg_neg_u64_overflow()).Finally, this commit adds a couple of tests for timestamps nearPOSTGRES_EPOCH_JDATE.Author: Joseph KoshakowReviewed-by: Tom Lane, Heikki Linnakangas, Jian HeDiscussion:https://postgr.es/m/CAAvxfHdBPOyEGS7s%2Bxf4iaW0-cgiq25jpYdWBqQqvLtLe_t6tw%40mail.gmail.com
1 parentad89d71 commit9e9a2b7

File tree

10 files changed

+189
-65
lines changed

10 files changed

+189
-65
lines changed

‎src/backend/utils/adt/cash.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ Datum
387387
cash_out(PG_FUNCTION_ARGS)
388388
{
389389
Cashvalue=PG_GETARG_CASH(0);
390+
uint64uvalue;
390391
char*result;
391392
charbuf[128];
392393
char*bufptr;
@@ -429,8 +430,6 @@ cash_out(PG_FUNCTION_ARGS)
429430

430431
if (value<0)
431432
{
432-
/* make the amount positive for digit-reconstruction loop */
433-
value=-value;
434433
/* set up formatting data */
435434
signsymbol= (*lconvert->negative_sign!='\0') ?lconvert->negative_sign :"-";
436435
sign_posn=lconvert->n_sign_posn;
@@ -445,6 +444,9 @@ cash_out(PG_FUNCTION_ARGS)
445444
sep_by_space=lconvert->p_sep_by_space;
446445
}
447446

447+
/* make the amount positive for digit-reconstruction loop */
448+
uvalue=pg_abs_s64(value);
449+
448450
/* we build the digits+decimal-point+sep string right-to-left in buf[] */
449451
bufptr=buf+sizeof(buf)-1;
450452
*bufptr='\0';
@@ -470,10 +472,10 @@ cash_out(PG_FUNCTION_ARGS)
470472
memcpy(bufptr,ssymbol,strlen(ssymbol));
471473
}
472474

473-
*(--bufptr)= ((uint64)value %10)+'0';
474-
value=((uint64)value) /10;
475+
*(--bufptr)= (uvalue %10)+'0';
476+
uvalue=uvalue /10;
475477
digit_pos--;
476-
}while (value||digit_pos >=0);
478+
}while (uvalue||digit_pos >=0);
477479

478480
/*----------
479481
* Now, attach currency symbol and sign symbol in the correct order.

‎src/backend/utils/adt/numeric.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8113,7 +8113,7 @@ int64_to_numericvar(int64 val, NumericVar *var)
81138113
if (val<0)
81148114
{
81158115
var->sign=NUMERIC_NEG;
8116-
uval=-val;
8116+
uval=pg_abs_s64(val);
81178117
}
81188118
else
81198119
{
@@ -11584,7 +11584,7 @@ power_var_int(const NumericVar *base, int exp, int exp_dscale,
1158411584
* Now we can proceed with the multiplications.
1158511585
*/
1158611586
neg= (exp<0);
11587-
mask=abs(exp);
11587+
mask=pg_abs_s32(exp);
1158811588

1158911589
init_var(&base_prod);
1159011590
set_var_from_var(base,&base_prod);

‎src/backend/utils/adt/numutils.c

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include<limits.h>
1919
#include<ctype.h>
2020

21+
#include"common/int.h"
2122
#include"port/pg_bitutils.h"
2223
#include"utils/builtins.h"
2324

@@ -131,6 +132,7 @@ pg_strtoint16_safe(const char *s, Node *escontext)
131132
uint16tmp=0;
132133
boolneg= false;
133134
unsignedchardigit;
135+
int16result;
134136

135137
/*
136138
* 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)
190192

191193
if (neg)
192194
{
193-
/* check the negative equivalent will fit without overflowing */
194-
if (unlikely(tmp> (uint16) (-(PG_INT16_MIN+1))+1))
195+
if (unlikely(pg_neg_u16_overflow(tmp,&result)))
195196
gotoout_of_range;
196-
return-((int16)tmp);
197+
returnresult;
197198
}
198199

199200
if (unlikely(tmp>PG_INT16_MAX))
@@ -333,10 +334,9 @@ pg_strtoint16_safe(const char *s, Node *escontext)
333334

334335
if (neg)
335336
{
336-
/* check the negative equivalent will fit without overflowing */
337-
if (tmp> (uint16) (-(PG_INT16_MIN+1))+1)
337+
if (unlikely(pg_neg_u16_overflow(tmp,&result)))
338338
gotoout_of_range;
339-
return-((int16)tmp);
339+
returnresult;
340340
}
341341

342342
if (tmp>PG_INT16_MAX)
@@ -393,6 +393,7 @@ pg_strtoint32_safe(const char *s, Node *escontext)
393393
uint32tmp=0;
394394
boolneg= false;
395395
unsignedchardigit;
396+
int32result;
396397

397398
/*
398399
* 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)
452453

453454
if (neg)
454455
{
455-
/* check the negative equivalent will fit without overflowing */
456-
if (unlikely(tmp> (uint32) (-(PG_INT32_MIN+1))+1))
456+
if (unlikely(pg_neg_u32_overflow(tmp,&result)))
457457
gotoout_of_range;
458-
return-((int32)tmp);
458+
returnresult;
459459
}
460460

461461
if (unlikely(tmp>PG_INT32_MAX))
@@ -595,10 +595,9 @@ pg_strtoint32_safe(const char *s, Node *escontext)
595595

596596
if (neg)
597597
{
598-
/* check the negative equivalent will fit without overflowing */
599-
if (tmp> (uint32) (-(PG_INT32_MIN+1))+1)
598+
if (unlikely(pg_neg_u32_overflow(tmp,&result)))
600599
gotoout_of_range;
601-
return-((int32)tmp);
600+
returnresult;
602601
}
603602

604603
if (tmp>PG_INT32_MAX)
@@ -655,6 +654,7 @@ pg_strtoint64_safe(const char *s, Node *escontext)
655654
uint64tmp=0;
656655
boolneg= false;
657656
unsignedchardigit;
657+
int64result;
658658

659659
/*
660660
* 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)
714714

715715
if (neg)
716716
{
717-
/* check the negative equivalent will fit without overflowing */
718-
if (unlikely(tmp> (uint64) (-(PG_INT64_MIN+1))+1))
717+
if (unlikely(pg_neg_u64_overflow(tmp,&result)))
719718
gotoout_of_range;
720-
return-((int64)tmp);
719+
returnresult;
721720
}
722721

723722
if (unlikely(tmp>PG_INT64_MAX))
@@ -857,10 +856,9 @@ pg_strtoint64_safe(const char *s, Node *escontext)
857856

858857
if (neg)
859858
{
860-
/* check the negative equivalent will fit without overflowing */
861-
if (tmp> (uint64) (-(PG_INT64_MIN+1))+1)
859+
if (unlikely(pg_neg_u64_overflow(tmp,&result)))
862860
gotoout_of_range;
863-
return-((int64)tmp);
861+
returnresult;
864862
}
865863

866864
if (tmp>PG_INT64_MAX)

‎src/backend/utils/adt/timestamp.c

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -618,19 +618,8 @@ make_timestamp_internal(int year, int month, int day,
618618
time= (((hour*MINS_PER_HOUR+min)*SECS_PER_MINUTE)
619619
*USECS_PER_SEC)+ (int64)rint(sec*USECS_PER_SEC);
620620

621-
result=date*USECS_PER_DAY+time;
622-
/* check for major overflow */
623-
if ((result-time) /USECS_PER_DAY!=date)
624-
ereport(ERROR,
625-
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
626-
errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
627-
year,month,day,
628-
hour,min,sec)));
629-
630-
/* check for just-barely overflow (okay except time-of-day wraps) */
631-
/* caution: we want to allow 1999-12-31 24:00:00 */
632-
if ((result<0&&date>0)||
633-
(result>0&&date<-1))
621+
if (unlikely(pg_mul_s64_overflow(date,USECS_PER_DAY,&result)||
622+
pg_add_s64_overflow(result,time,&result)))
634623
ereport(ERROR,
635624
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
636625
errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
@@ -2010,17 +1999,8 @@ tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
20101999
date=date2j(tm->tm_year,tm->tm_mon,tm->tm_mday)-POSTGRES_EPOCH_JDATE;
20112000
time=time2t(tm->tm_hour,tm->tm_min,tm->tm_sec,fsec);
20122001

2013-
*result=date*USECS_PER_DAY+time;
2014-
/* check for major overflow */
2015-
if ((*result-time) /USECS_PER_DAY!=date)
2016-
{
2017-
*result=0;/* keep compiler quiet */
2018-
return-1;
2019-
}
2020-
/* check for just-barely overflow (okay except time-of-day wraps) */
2021-
/* caution: we want to allow 1999-12-31 24:00:00 */
2022-
if ((*result<0&&date>0)||
2023-
(*result>0&&date<-1))
2002+
if (unlikely(pg_mul_s64_overflow(date,USECS_PER_DAY,result)||
2003+
pg_add_s64_overflow(*result,time,result)))
20242004
{
20252005
*result=0;/* keep compiler quiet */
20262006
return-1;

‎src/include/common/int.h

Lines changed: 123 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,35 @@
2323

2424
/*---------
2525
* The following guidelines apply to all the overflow routines:
26-
* - If a + b overflows, return true, otherwise store the result of a + b
27-
* into *result. The content of *result is implementation defined in case of
28-
* overflow.
29-
* - If a - b overflows, return true, otherwise store the result of a - b
30-
* into *result. The content of *result is implementation defined in case of
31-
* overflow.
32-
* - If a * b overflows, return true, otherwise store the result of a * b
33-
* into *result. The content of *result is implementation defined in case of
26+
*
27+
* If the result overflows, return true, otherwise store the result into
28+
* *result. The content of *result is implementation defined in case of
3429
* overflow.
30+
*
31+
* bool pg_add_*_overflow(a, b, *result)
32+
*
33+
* Calculate a + b
34+
*
35+
* bool pg_sub_*_overflow(a, b, *result)
36+
*
37+
* Calculate a - b
38+
*
39+
* bool pg_mul_*_overflow(a, b, *result)
40+
*
41+
* Calculate a * b
42+
*
43+
* bool pg_neg_*_overflow(a, *result)
44+
*
45+
* Calculate -a
46+
*
47+
*
48+
* In addition, this file contains:
49+
*
50+
* <unsigned int type> pg_abs_*(<signed int type> a)
51+
*
52+
* Calculate absolute value of a. Unlike the standard library abs()
53+
* and labs() functions, the return type is unsigned, so the operation
54+
* cannot overflow.
3555
*---------
3656
*/
3757

@@ -97,6 +117,17 @@ pg_mul_s16_overflow(int16 a, int16 b, int16 *result)
97117
#endif
98118
}
99119

120+
staticinlineuint16
121+
pg_abs_s16(int16a)
122+
{
123+
/*
124+
* This first widens the argument from int16 to int32 for use with abs().
125+
* The result is then narrowed from int32 to uint16. This prevents any
126+
* possibility of overflow.
127+
*/
128+
return (uint16)abs((int32)a);
129+
}
130+
100131
/*
101132
* INT32
102133
*/
@@ -154,6 +185,17 @@ pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
154185
#endif
155186
}
156187

188+
staticinlineuint32
189+
pg_abs_s32(int32a)
190+
{
191+
/*
192+
* This first widens the argument from int32 to int64 for use with
193+
* i64abs(). The result is then narrowed from int64 to uint32. This
194+
* prevents any possibility of overflow.
195+
*/
196+
return (uint32)i64abs((int64)a);
197+
}
198+
157199
/*
158200
* INT64
159201
*/
@@ -258,6 +300,14 @@ pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
258300
#endif
259301
}
260302

303+
staticinlineuint64
304+
pg_abs_s64(int64a)
305+
{
306+
if (unlikely(a==PG_INT64_MIN))
307+
return (uint64)PG_INT64_MAX+1;
308+
return (uint64)i64abs(a);
309+
}
310+
261311
/*------------------------------------------------------------------------
262312
* Overflow routines for unsigned integers
263313
*------------------------------------------------------------------------
@@ -318,6 +368,24 @@ pg_mul_u16_overflow(uint16 a, uint16 b, uint16 *result)
318368
#endif
319369
}
320370

371+
staticinlinebool
372+
pg_neg_u16_overflow(uint16a,int16*result)
373+
{
374+
#if defined(HAVE__BUILTIN_OP_OVERFLOW)
375+
return__builtin_sub_overflow(0,a,result);
376+
#else
377+
int32res=-((int32)a);
378+
379+
if (unlikely(res<PG_INT16_MIN))
380+
{
381+
*result=0x5EED;/* to avoid spurious warnings */
382+
return true;
383+
}
384+
*result=res;
385+
return false;
386+
#endif
387+
}
388+
321389
/*
322390
* INT32
323391
*/
@@ -373,6 +441,24 @@ pg_mul_u32_overflow(uint32 a, uint32 b, uint32 *result)
373441
#endif
374442
}
375443

444+
staticinlinebool
445+
pg_neg_u32_overflow(uint32a,int32*result)
446+
{
447+
#if defined(HAVE__BUILTIN_OP_OVERFLOW)
448+
return__builtin_sub_overflow(0,a,result);
449+
#else
450+
int64res=-((int64)a);
451+
452+
if (unlikely(res<PG_INT32_MIN))
453+
{
454+
*result=0x5EED;/* to avoid spurious warnings */
455+
return true;
456+
}
457+
*result=res;
458+
return false;
459+
#endif
460+
}
461+
376462
/*
377463
* UINT64
378464
*/
@@ -438,6 +524,35 @@ pg_mul_u64_overflow(uint64 a, uint64 b, uint64 *result)
438524
#endif
439525
}
440526

527+
staticinlinebool
528+
pg_neg_u64_overflow(uint64a,int64*result)
529+
{
530+
#if defined(HAVE__BUILTIN_OP_OVERFLOW)
531+
return__builtin_sub_overflow(0,a,result);
532+
#elif defined(HAVE_INT128)
533+
int128res=-((int128)a);
534+
535+
if (unlikely(res<PG_INT64_MIN))
536+
{
537+
*result=0x5EED;/* to avoid spurious warnings */
538+
return true;
539+
}
540+
*result=res;
541+
return false;
542+
#else
543+
if (unlikely(a> (uint64)PG_INT64_MAX+1))
544+
{
545+
*result=0x5EED;/* to avoid spurious warnings */
546+
return true;
547+
}
548+
if (unlikely(a== (uint64)PG_INT64_MAX+1))
549+
*result=PG_INT64_MIN;
550+
else
551+
*result=-((int64)a);
552+
return false;
553+
#endif
554+
}
555+
441556
/*------------------------------------------------------------------------
442557
*
443558
* Comparison routines for integer types.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp