1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Fix missing money overflow checks for INT64_MIN / -1

Similar to what 1f7cb5c30 did for the INT types, protect against
overflow when dividing the lowest possible money value by -1.  This
cannot be represented on a two's complement machine.

Without this check, the result depends on the machine, and in the worst
case, could result in a crash.  With the fix installed, this will now
result in:

ERROR:  money out of range

Bug: #19585
Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Reported-by: Michael Malis <malis@pgrust.com>
Reviewed-by: Tristan Partin <tristan@partin.io>
Reviewed-by: Rafia Sabih <rafia.pghackers@gmail.com>
Discussion: https://postgr.es/m/19586-bb603bf5ad9934dd%40postgresql.org
Discussion: https://postgr.es/m/CAB8bMisnXJVXte6s3kUOpuuAY9%3D9kehG6MMX-%2BTQoFsSGan22Q%40mail.gmail.com
Backpatch-through: 14
This commit is contained in:
David Rowley
2026-08-04 18:00:49 +12:00
parent cce758797f
commit 1416f304d2
3 changed files with 28 additions and 0 deletions

View File

@@ -160,6 +160,22 @@ cash_div_int64(Cash c, int64 i)
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
/*
* INT64_MIN / -1 is problematic, since the result can't be represented on
* a two's-complement machine. Some machines produce INT64_MIN, some
* produce zero, some throw an exception. We can dodge the problem by
* recognizing that division by -1 is the same as negation.
*/
if (i == -1)
{
if (unlikely(c == PG_INT64_MIN))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("money out of range")));
return -c;
}
/* No overflow is possible */
return c / i;
}

View File

@@ -539,6 +539,14 @@ SELECT '-1'::money / 1.175494e-38::float4;
ERROR: money out of range
SELECT '92233720368547758.07'::money * 2::int4;
ERROR: money out of range
SELECT '-92233720368547758.08'::money * -1::int8;
ERROR: money out of range
SELECT '-92233720368547758.08'::money / -1::int8;
ERROR: money out of range
SELECT '-92233720368547758.08'::money / -1::int4;
ERROR: money out of range
SELECT '-92233720368547758.08'::money / -1::int2;
ERROR: money out of range
SELECT '1'::money / 0::int2;
ERROR: division by zero
SELECT '42'::money * 'inf'::float8;

View File

@@ -142,6 +142,10 @@ SELECT '-92233720368547758.08'::money - '0.01'::money;
SELECT '92233720368547758.07'::money * 2::float8;
SELECT '-1'::money / 1.175494e-38::float4;
SELECT '92233720368547758.07'::money * 2::int4;
SELECT '-92233720368547758.08'::money * -1::int8;
SELECT '-92233720368547758.08'::money / -1::int8;
SELECT '-92233720368547758.08'::money / -1::int4;
SELECT '-92233720368547758.08'::money / -1::int2;
SELECT '1'::money / 0::int2;
SELECT '42'::money * 'inf'::float8;
SELECT '42'::money * '-inf'::float8;