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

Commiteb865db

Browse files
committed
Improve handling of INT_MIN / -1 and related cases.
Some platforms throw an exception for this division, rather than returninga necessarily-overflowed result. Since we were testing for overflow afterthe fact, an exception isn't nice. We can avoid the problem by treatingdivision by -1 as negation.Add some regression tests so that we'll find out if any compilers try tooptimize away the overflow check conditions.Back-patch of commit1f7cb5c.Per discussion with Xi Wang, though this is different from the patch hesubmitted.
1 parent15939a7 commiteb865db

File tree

9 files changed

+232
-83
lines changed

9 files changed

+232
-83
lines changed

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

Lines changed: 56 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -680,18 +680,6 @@ int4mul(PG_FUNCTION_ARGS)
680680
int32arg2=PG_GETARG_INT32(1);
681681
int32result;
682682

683-
#ifdefWIN32
684-
685-
/*
686-
* Win32 doesn't throw a catchable exception for SELECT -2147483648 *
687-
* (-1); -- INT_MIN
688-
*/
689-
if (arg2==-1&&arg1==INT_MIN)
690-
ereport(ERROR,
691-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
692-
errmsg("integer out of range")));
693-
#endif
694-
695683
result=arg1*arg2;
696684

697685
/*
@@ -708,7 +696,8 @@ int4mul(PG_FUNCTION_ARGS)
708696
if (!(arg1 >= (int32)SHRT_MIN&&arg1 <= (int32)SHRT_MAX&&
709697
arg2 >= (int32)SHRT_MIN&&arg2 <= (int32)SHRT_MAX)&&
710698
arg2!=0&&
711-
(result /arg2!=arg1|| (arg2==-1&&arg1<0&&result<0)))
699+
((arg2==-1&&arg1<0&&result<0)||
700+
result /arg2!=arg1))
712701
ereport(ERROR,
713702
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
714703
errmsg("integer out of range")));
@@ -731,30 +720,27 @@ int4div(PG_FUNCTION_ARGS)
731720
PG_RETURN_NULL();
732721
}
733722

734-
#ifdefWIN32
735-
736723
/*
737-
* Win32 doesn't throw a catchable exception for SELECT -2147483648 /
738-
* (-1); -- INT_MIN
724+
* INT_MIN / -1 is problematic, since the result can't be represented on a
725+
* two's-complement machine. Some machines produce INT_MIN, some produce
726+
* zero, some throw an exception. We can dodge the problem by recognizing
727+
* that division by -1 is the same as negation.
739728
*/
740-
if (arg2==-1&&arg1==INT_MIN)
741-
ereport(ERROR,
742-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
743-
errmsg("integer out of range")));
744-
#endif
729+
if (arg2==-1)
730+
{
731+
result=-arg1;
732+
/* overflow check (needed for INT_MIN) */
733+
if (arg1!=0&&SAMESIGN(result,arg1))
734+
ereport(ERROR,
735+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
736+
errmsg("integer out of range")));
737+
PG_RETURN_INT32(result);
738+
}
739+
740+
/* No overflow is possible */
745741

746742
result=arg1 /arg2;
747743

748-
/*
749-
* Overflow check.The only possible overflow case is for arg1 = INT_MIN,
750-
* arg2 = -1, where the correct result is -INT_MIN, which can't be
751-
* represented on a two's-complement machine. Most machines produce
752-
* INT_MIN but it seems some produce zero.
753-
*/
754-
if (arg2==-1&&arg1<0&&result <=0)
755-
ereport(ERROR,
756-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
757-
errmsg("integer out of range")));
758744
PG_RETURN_INT32(result);
759745
}
760746

@@ -876,18 +862,27 @@ int2div(PG_FUNCTION_ARGS)
876862
PG_RETURN_NULL();
877863
}
878864

879-
result=arg1 /arg2;
880-
881865
/*
882-
*Overflow check.The only possible overflow case is for arg1 =
883-
*SHRT_MIN, arg2 = -1, where the correct result is -SHRT_MIN,which can't
884-
*be represented on a two's-complement machine.Most machines produce
885-
*SHRT_MIN but it seems some produce zero.
866+
*SHRT_MIN / -1 is problematic, since the result can't be represented on
867+
*a two's-complement machine. Some machines produceSHRT_MIN,some
868+
*produce zero, some throw an exception.We can dodge the problem by
869+
*recognizing that division by -1 is the same as negation.
886870
*/
887-
if (arg2==-1&&arg1<0&&result <=0)
888-
ereport(ERROR,
889-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
890-
errmsg("smallint out of range")));
871+
if (arg2==-1)
872+
{
873+
result=-arg1;
874+
/* overflow check (needed for SHRT_MIN) */
875+
if (arg1!=0&&SAMESIGN(result,arg1))
876+
ereport(ERROR,
877+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
878+
errmsg("smallint out of range")));
879+
PG_RETURN_INT16(result);
880+
}
881+
882+
/* No overflow is possible */
883+
884+
result=arg1 /arg2;
885+
891886
PG_RETURN_INT16(result);
892887
}
893888

@@ -1064,18 +1059,27 @@ int42div(PG_FUNCTION_ARGS)
10641059
PG_RETURN_NULL();
10651060
}
10661061

1067-
result=arg1 /arg2;
1068-
10691062
/*
1070-
*Overflow check.The only possible overflow case is for arg1 = INT_MIN,
1071-
*arg2 = -1, where the correct result is -INT_MIN,which can't be
1072-
*represented on a two's-complement machine.Most machines produce
1073-
*INT_MIN but it seems some produce zero.
1063+
*INT_MIN / -1 is problematic, since the result can't be represented on a
1064+
*two's-complement machine. Some machines produceINT_MIN,some produce
1065+
*zero, some throw an exception.We can dodge the problem by recognizing
1066+
*that division by -1 is the same as negation.
10741067
*/
1075-
if (arg2==-1&&arg1<0&&result <=0)
1076-
ereport(ERROR,
1077-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1078-
errmsg("integer out of range")));
1068+
if (arg2==-1)
1069+
{
1070+
result=-arg1;
1071+
/* overflow check (needed for INT_MIN) */
1072+
if (arg1!=0&&SAMESIGN(result,arg1))
1073+
ereport(ERROR,
1074+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1075+
errmsg("integer out of range")));
1076+
PG_RETURN_INT32(result);
1077+
}
1078+
1079+
/* No overflow is possible */
1080+
1081+
result=arg1 /arg2;
1082+
10791083
PG_RETURN_INT32(result);
10801084
}
10811085

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

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,8 @@ int8mul(PG_FUNCTION_ARGS)
576576
if (arg1!= (int64) ((int32)arg1)||arg2!= (int64) ((int32)arg2))
577577
{
578578
if (arg2!=0&&
579-
(result /arg2!=arg1|| (arg2==-1&&arg1<0&&result<0)))
579+
((arg2==-1&&arg1<0&&result<0)||
580+
result /arg2!=arg1))
580581
ereport(ERROR,
581582
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
582583
errmsg("bigint out of range")));
@@ -600,18 +601,27 @@ int8div(PG_FUNCTION_ARGS)
600601
PG_RETURN_NULL();
601602
}
602603

603-
result=arg1 /arg2;
604-
605604
/*
606-
*Overflow check.The only possible overflow case is for arg1 =
607-
*INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN,which
608-
*can't be represented on a two's-complement machine.Most machines
609-
*produce INT64_MIN but it seems some produce zero.
605+
*INT64_MIN / -1 is problematic, since the result can't be represented on
606+
*a two's-complement machine. Some machines produceINT64_MIN,some
607+
*produce zero, some throw an exception. We can dodge the problem by
608+
*recognizing that division by -1 is the same as negation.
610609
*/
611-
if (arg2==-1&&arg1<0&&result <=0)
612-
ereport(ERROR,
613-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
614-
errmsg("bigint out of range")));
610+
if (arg2==-1)
611+
{
612+
result=-arg1;
613+
/* overflow check (needed for INT64_MIN) */
614+
if (arg1!=0&&SAMESIGN(result,arg1))
615+
ereport(ERROR,
616+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
617+
errmsg("bigint out of range")));
618+
PG_RETURN_INT64(result);
619+
}
620+
621+
/* No overflow is possible */
622+
623+
result=arg1 /arg2;
624+
615625
PG_RETURN_INT64(result);
616626
}
617627

@@ -840,18 +850,27 @@ int84div(PG_FUNCTION_ARGS)
840850
PG_RETURN_NULL();
841851
}
842852

843-
result=arg1 /arg2;
844-
845853
/*
846-
*Overflow check.The only possible overflow case is for arg1 =
847-
*INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN,which
848-
*can't be represented on a two's-complement machine.Most machines
849-
*produce INT64_MIN but it seems some produce zero.
854+
*INT64_MIN / -1 is problematic, since the result can't be represented on
855+
*a two's-complement machine. Some machines produceINT64_MIN,some
856+
*produce zero, some throw an exception. We can dodge the problem by
857+
*recognizing that division by -1 is the same as negation.
850858
*/
851-
if (arg2==-1&&arg1<0&&result <=0)
852-
ereport(ERROR,
853-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
854-
errmsg("bigint out of range")));
859+
if (arg2==-1)
860+
{
861+
result=-arg1;
862+
/* overflow check (needed for INT64_MIN) */
863+
if (arg1!=0&&SAMESIGN(result,arg1))
864+
ereport(ERROR,
865+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
866+
errmsg("bigint out of range")));
867+
PG_RETURN_INT64(result);
868+
}
869+
870+
/* No overflow is possible */
871+
872+
result=arg1 /arg2;
873+
855874
PG_RETURN_INT64(result);
856875
}
857876

@@ -1028,18 +1047,27 @@ int82div(PG_FUNCTION_ARGS)
10281047
PG_RETURN_NULL();
10291048
}
10301049

1031-
result=arg1 /arg2;
1032-
10331050
/*
1034-
*Overflow check.The only possible overflow case is for arg1 =
1035-
*INT64_MIN, arg2 = -1, where the correct result is -INT64_MIN,which
1036-
*can't be represented on a two's-complement machine.Most machines
1037-
*produce INT64_MIN but it seems some produce zero.
1051+
*INT64_MIN / -1 is problematic, since the result can't be represented on
1052+
*a two's-complement machine. Some machines produceINT64_MIN,some
1053+
*produce zero, some throw an exception. We can dodge the problem by
1054+
*recognizing that division by -1 is the same as negation.
10381055
*/
1039-
if (arg2==-1&&arg1<0&&result <=0)
1040-
ereport(ERROR,
1041-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1042-
errmsg("bigint out of range")));
1056+
if (arg2==-1)
1057+
{
1058+
result=-arg1;
1059+
/* overflow check (needed for INT64_MIN) */
1060+
if (arg1!=0&&SAMESIGN(result,arg1))
1061+
ereport(ERROR,
1062+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1063+
errmsg("bigint out of range")));
1064+
PG_RETURN_INT64(result);
1065+
}
1066+
1067+
/* No overflow is possible */
1068+
1069+
result=arg1 /arg2;
1070+
10431071
PG_RETURN_INT64(result);
10441072
}
10451073

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,14 @@ SELECT '' AS five, i.f1, i.f1 / int4 '2' AS x FROM INT2_TBL i;
244244
| -32767 | -16383
245245
(5 rows)
246246

247+
-- check sane handling of INT16_MIN overflow cases
248+
SELECT (-32768)::int2 * (-1)::int2;
249+
ERROR: smallint out of range
250+
SELECT (-32768)::int2 / (-1)::int2;
251+
ERROR: smallint out of range
252+
SELECT (-32768)::int2 % (-1)::int2;
253+
?column?
254+
----------
255+
0
256+
(1 row)
257+

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,24 @@ SELECT (2 + 2) / 2 AS two;
331331
2
332332
(1 row)
333333

334+
-- check sane handling of INT_MIN overflow cases
335+
SELECT (-2147483648)::int4 * (-1)::int4;
336+
ERROR: integer out of range
337+
SELECT (-2147483648)::int4 / (-1)::int4;
338+
ERROR: integer out of range
339+
SELECT (-2147483648)::int4 % (-1)::int4;
340+
?column?
341+
----------
342+
0
343+
(1 row)
344+
345+
SELECT (-2147483648)::int4 * (-1)::int2;
346+
ERROR: integer out of range
347+
SELECT (-2147483648)::int4 / (-1)::int2;
348+
ERROR: integer out of range
349+
SELECT (-2147483648)::int4 % (-1)::int2;
350+
?column?
351+
----------
352+
0
353+
(1 row)
354+

‎src/test/regress/expected/int8-exp-three-digits.out

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,3 +802,34 @@ SELECT * FROM generate_series('+4567890123456789'::int8, '+4567890123456799'::in
802802
4567890123456799
803803
(6 rows)
804804

805+
-- check sane handling of INT64_MIN overflow cases
806+
SELECT (-9223372036854775808)::int8 * (-1)::int8;
807+
ERROR: bigint out of range
808+
SELECT (-9223372036854775808)::int8 / (-1)::int8;
809+
ERROR: bigint out of range
810+
SELECT (-9223372036854775808)::int8 % (-1)::int8;
811+
?column?
812+
----------
813+
0
814+
(1 row)
815+
816+
SELECT (-9223372036854775808)::int8 * (-1)::int4;
817+
ERROR: bigint out of range
818+
SELECT (-9223372036854775808)::int8 / (-1)::int4;
819+
ERROR: bigint out of range
820+
SELECT (-9223372036854775808)::int8 % (-1)::int4;
821+
?column?
822+
----------
823+
0
824+
(1 row)
825+
826+
SELECT (-9223372036854775808)::int8 * (-1)::int2;
827+
ERROR: bigint out of range
828+
SELECT (-9223372036854775808)::int8 / (-1)::int2;
829+
ERROR: bigint out of range
830+
SELECT (-9223372036854775808)::int8 % (-1)::int2;
831+
?column?
832+
----------
833+
0
834+
(1 row)
835+

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,3 +802,34 @@ SELECT * FROM generate_series('+4567890123456789'::int8, '+4567890123456799'::in
802802
4567890123456799
803803
(6 rows)
804804

805+
-- check sane handling of INT64_MIN overflow cases
806+
SELECT (-9223372036854775808)::int8 * (-1)::int8;
807+
ERROR: bigint out of range
808+
SELECT (-9223372036854775808)::int8 / (-1)::int8;
809+
ERROR: bigint out of range
810+
SELECT (-9223372036854775808)::int8 % (-1)::int8;
811+
?column?
812+
----------
813+
0
814+
(1 row)
815+
816+
SELECT (-9223372036854775808)::int8 * (-1)::int4;
817+
ERROR: bigint out of range
818+
SELECT (-9223372036854775808)::int8 / (-1)::int4;
819+
ERROR: bigint out of range
820+
SELECT (-9223372036854775808)::int8 % (-1)::int4;
821+
?column?
822+
----------
823+
0
824+
(1 row)
825+
826+
SELECT (-9223372036854775808)::int8 * (-1)::int2;
827+
ERROR: bigint out of range
828+
SELECT (-9223372036854775808)::int8 / (-1)::int2;
829+
ERROR: bigint out of range
830+
SELECT (-9223372036854775808)::int8 % (-1)::int2;
831+
?column?
832+
----------
833+
0
834+
(1 row)
835+

‎src/test/regress/sql/int2.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,7 @@ SELECT '' AS five, i.f1, i.f1 / int2 '2' AS x FROM INT2_TBL i;
8686

8787
SELECT''AS five,i.f1,i.f1/ int4'2'AS xFROM INT2_TBL i;
8888

89+
-- check sane handling of INT16_MIN overflow cases
90+
SELECT (-32768)::int2* (-1)::int2;
91+
SELECT (-32768)::int2/ (-1)::int2;
92+
SELECT (-32768)::int2 % (-1)::int2;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp