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

Commitb49b7f9

Browse files
committed
Fix integer-overflow edge case detection in interval_mul and pgbench.
This patch adopts the overflow check logic introduced by commitcbdb8b4into two more places. interval_mul() failed to notice if it computed anew microseconds value that was one more than INT64_MAX, and pgbench'sdouble-to-int64 logic had the same sorts of edge-case problems thatcbdb8b4 fixed in the core code.To make this easier to get right in future, put the guts of the checksinto new macros in c.h, and add commentary about how to use the macroscorrectly.Back-patch to all supported branches, as we did with the previous fix.Yuya WatariDiscussion:https://postgr.es/m/CAJ2pMkbkkFw2hb9Qb1Zj8d06EhWAQXFLy73St4qWv6aX=vqnjw@mail.gmail.com
1 parentfb53c4c commitb49b7f9

File tree

7 files changed

+45
-57
lines changed

7 files changed

+45
-57
lines changed

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

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,15 +1362,8 @@ dtoi4(PG_FUNCTION_ARGS)
13621362
*/
13631363
num=rint(num);
13641364

1365-
/*
1366-
* Range check. We must be careful here that the boundary values are
1367-
* expressed exactly in the float domain. We expect PG_INT32_MIN to be an
1368-
* exact power of 2, so it will be represented exactly; but PG_INT32_MAX
1369-
* isn't, and might get rounded off, so avoid using it.
1370-
*/
1371-
if (unlikely(num< (float8)PG_INT32_MIN||
1372-
num >=-((float8)PG_INT32_MIN)||
1373-
isnan(num)))
1365+
/* Range check */
1366+
if (unlikely(isnan(num)|| !FLOAT8_FITS_IN_INT32(num)))
13741367
ereport(ERROR,
13751368
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
13761369
errmsg("integer out of range")));
@@ -1394,15 +1387,8 @@ dtoi2(PG_FUNCTION_ARGS)
13941387
*/
13951388
num=rint(num);
13961389

1397-
/*
1398-
* Range check. We must be careful here that the boundary values are
1399-
* expressed exactly in the float domain. We expect PG_INT16_MIN to be an
1400-
* exact power of 2, so it will be represented exactly; but PG_INT16_MAX
1401-
* isn't, and might get rounded off, so avoid using it.
1402-
*/
1403-
if (unlikely(num< (float8)PG_INT16_MIN||
1404-
num >=-((float8)PG_INT16_MIN)||
1405-
isnan(num)))
1390+
/* Range check */
1391+
if (unlikely(isnan(num)|| !FLOAT8_FITS_IN_INT16(num)))
14061392
ereport(ERROR,
14071393
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
14081394
errmsg("smallint out of range")));
@@ -1450,15 +1436,8 @@ ftoi4(PG_FUNCTION_ARGS)
14501436
*/
14511437
num=rint(num);
14521438

1453-
/*
1454-
* Range check. We must be careful here that the boundary values are
1455-
* expressed exactly in the float domain. We expect PG_INT32_MIN to be an
1456-
* exact power of 2, so it will be represented exactly; but PG_INT32_MAX
1457-
* isn't, and might get rounded off, so avoid using it.
1458-
*/
1459-
if (unlikely(num< (float4)PG_INT32_MIN||
1460-
num >=-((float4)PG_INT32_MIN)||
1461-
isnan(num)))
1439+
/* Range check */
1440+
if (unlikely(isnan(num)|| !FLOAT4_FITS_IN_INT32(num)))
14621441
ereport(ERROR,
14631442
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
14641443
errmsg("integer out of range")));
@@ -1482,15 +1461,8 @@ ftoi2(PG_FUNCTION_ARGS)
14821461
*/
14831462
num=rint(num);
14841463

1485-
/*
1486-
* Range check. We must be careful here that the boundary values are
1487-
* expressed exactly in the float domain. We expect PG_INT16_MIN to be an
1488-
* exact power of 2, so it will be represented exactly; but PG_INT16_MAX
1489-
* isn't, and might get rounded off, so avoid using it.
1490-
*/
1491-
if (unlikely(num< (float4)PG_INT16_MIN||
1492-
num >=-((float4)PG_INT16_MIN)||
1493-
isnan(num)))
1464+
/* Range check */
1465+
if (unlikely(isnan(num)|| !FLOAT4_FITS_IN_INT16(num)))
14941466
ereport(ERROR,
14951467
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
14961468
errmsg("smallint out of range")));

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

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,15 +1213,8 @@ dtoi8(PG_FUNCTION_ARGS)
12131213
*/
12141214
num=rint(num);
12151215

1216-
/*
1217-
* Range check. We must be careful here that the boundary values are
1218-
* expressed exactly in the float domain. We expect PG_INT64_MIN to be an
1219-
* exact power of 2, so it will be represented exactly; but PG_INT64_MAX
1220-
* isn't, and might get rounded off, so avoid using it.
1221-
*/
1222-
if (unlikely(num< (float8)PG_INT64_MIN||
1223-
num >=-((float8)PG_INT64_MIN)||
1224-
isnan(num)))
1216+
/* Range check */
1217+
if (unlikely(isnan(num)|| !FLOAT8_FITS_IN_INT64(num)))
12251218
ereport(ERROR,
12261219
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
12271220
errmsg("bigint out of range")));
@@ -1255,15 +1248,8 @@ ftoi8(PG_FUNCTION_ARGS)
12551248
*/
12561249
num=rint(num);
12571250

1258-
/*
1259-
* Range check. We must be careful here that the boundary values are
1260-
* expressed exactly in the float domain. We expect PG_INT64_MIN to be an
1261-
* exact power of 2, so it will be represented exactly; but PG_INT64_MAX
1262-
* isn't, and might get rounded off, so avoid using it.
1263-
*/
1264-
if (unlikely(num< (float4)PG_INT64_MIN||
1265-
num >=-((float4)PG_INT64_MIN)||
1266-
isnan(num)))
1251+
/* Range check */
1252+
if (unlikely(isnan(num)|| !FLOAT4_FITS_IN_INT64(num)))
12671253
ereport(ERROR,
12681254
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
12691255
errmsg("bigint out of range")));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3200,7 +3200,7 @@ interval_mul(PG_FUNCTION_ARGS)
32003200
/* cascade units down */
32013201
result->day+= (int32)month_remainder_days;
32023202
result_double=rint(span->time*factor+sec_remainder*USECS_PER_SEC);
3203-
if (result_double>PG_INT64_MAX||result_double<PG_INT64_MIN)
3203+
if (isnan(result_double)||!FLOAT8_FITS_IN_INT64(result_double))
32043204
ereport(ERROR,
32053205
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
32063206
errmsg("interval out of range")));

‎src/bin/pgbench/pgbench.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,9 +1617,9 @@ coerceToInt(PgBenchValue *pval, int64 *ival)
16171617
}
16181618
elseif (pval->type==PGBT_DOUBLE)
16191619
{
1620-
doubledval=pval->u.dval;
1620+
doubledval=rint(pval->u.dval);
16211621

1622-
if (dval<PG_INT64_MIN||PG_INT64_MAX<dval)
1622+
if (isnan(dval)||!FLOAT8_FITS_IN_INT64(dval))
16231623
{
16241624
fprintf(stderr,"double to int overflow for %f\n",dval);
16251625
return false;

‎src/include/c.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,30 @@ extern void ExceptionalCondition(const char *conditionName,
983983
*_start++ = 0; \
984984
} while (0)
985985

986+
/*
987+
* Macros for range-checking float values before converting to integer.
988+
* We must be careful here that the boundary values are expressed exactly
989+
* in the float domain. PG_INTnn_MIN is an exact power of 2, so it will
990+
* be represented exactly; but PG_INTnn_MAX isn't, and might get rounded
991+
* off, so avoid using that.
992+
* The input must be rounded to an integer beforehand, typically with rint(),
993+
* else we might draw the wrong conclusion about close-to-the-limit values.
994+
* These macros will do the right thing for Inf, but not necessarily for NaN,
995+
* so check isnan(num) first if that's a possibility.
996+
*/
997+
#defineFLOAT4_FITS_IN_INT16(num) \
998+
((num) >= (float4) PG_INT16_MIN && (num) < -((float4) PG_INT16_MIN))
999+
#defineFLOAT4_FITS_IN_INT32(num) \
1000+
((num) >= (float4) PG_INT32_MIN && (num) < -((float4) PG_INT32_MIN))
1001+
#defineFLOAT4_FITS_IN_INT64(num) \
1002+
((num) >= (float4) PG_INT64_MIN && (num) < -((float4) PG_INT64_MIN))
1003+
#defineFLOAT8_FITS_IN_INT16(num) \
1004+
((num) >= (float8) PG_INT16_MIN && (num) < -((float8) PG_INT16_MIN))
1005+
#defineFLOAT8_FITS_IN_INT32(num) \
1006+
((num) >= (float8) PG_INT32_MIN && (num) < -((float8) PG_INT32_MIN))
1007+
#defineFLOAT8_FITS_IN_INT64(num) \
1008+
((num) >= (float8) PG_INT64_MIN && (num) < -((float8) PG_INT64_MIN))
1009+
9861010

9871011
/* ----------------------------------------------------------------
9881012
*Section 8:random stuff

‎src/test/regress/expected/interval.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ INSERT INTO INTERVAL_TBL_OF (f1) VALUES ('-2147483648 years');
232232
ERROR: interval out of range
233233
LINE 1: INSERT INTO INTERVAL_TBL_OF (f1) VALUES ('-2147483648 years'...
234234
^
235+
-- Test edge-case overflow detection in interval multiplication
236+
select extract(epoch from '256 microseconds'::interval * (2^55)::float8);
237+
ERROR: interval out of range
235238
SELECT r1.*, r2.*
236239
FROM INTERVAL_TBL_OF r1, INTERVAL_TBL_OF r2
237240
WHERE r1.f1 > r2.f1

‎src/test/regress/sql/interval.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ INSERT INTO INTERVAL_TBL_OF (f1) VALUES ('-2147483649 days');
7373
INSERT INTO INTERVAL_TBL_OF (f1)VALUES ('2147483647 years');
7474
INSERT INTO INTERVAL_TBL_OF (f1)VALUES ('-2147483648 years');
7575

76+
-- Test edge-case overflow detection in interval multiplication
77+
select extract(epochfrom'256 microseconds'::interval* (2^55)::float8);
78+
7679
SELECT r1.*, r2.*
7780
FROM INTERVAL_TBL_OF r1, INTERVAL_TBL_OF r2
7881
WHEREr1.f1>r2.f1

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp