BUG #19593: area(circle) silently returns Infinity instead of raising "value out of range: overflow"

From: PG Bug reporting form <noreply(at)postgresql(dot)org>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Cc: malis(at)pgrust(dot)com
Subject: BUG #19593: area(circle) silently returns Infinity instead of raising "value out of range: overflow"
Date: 2026-08-01 03:07:25
Message-ID: 19593-d80bd21f90d32234@postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 19593
Logged by: Michael Malis
Email address: malis(at)pgrust(dot)com
PostgreSQL version: 18.3
Operating system: Debian (official Docker image), aarch64
Description:

I'm not sure what you'll want to do with this one, but I figured I would at
least report it. The cause seems to be a bug in gcc.

area(circle) returns Infinity where it must raise ERROR 22003 "value out of
range: overflow". The overflow check in float8_mul() is present in the
source
but is absent from the generated code, because gcc 13 and later delete it at
-O1 and above.

The same binary raises the error correctly for the equivalent SQL-level
expression, and for a circle whose radius overflows one step earlier, so
this
is not "PostgreSQL does not check circle areas".

-- WRONG: no error, returns Infinity
SELECT area(circle '<(0,0),1e154>');
area
------------------------
Infinity

-- CORRECT (control): the *inner* multiply overflows, so the surviving
-- check fires
SELECT area(circle '<(0,0),1e200>');
ERROR: value out of range: overflow

-- CORRECT (control): the same arithmetic, expressed in SQL
SELECT 1e154::float8 * 1e154::float8 * pi();
ERROR: value out of range: overflow

-- sane value, for reference
SELECT area(circle '<(0,0),1e10>');
area
-------------------------
3.1415926535897933e+20

1e154 * 1e154 = 1e308, which is finite (below DBL_MAX); multiplying that by
pi
overflows. Behaviour is identical whether the expression is constant-folded
at
plan time or evaluated at runtime:

SELECT area(c) FROM (VALUES (circle '<(0,0),1e154>')) t(c); --
Infinity

NaN and Infinity radii behave correctly (NaN -> NaN, Infinity -> Infinity).

WHERE IT COMES FROM

src/backend/utils/adt/geo_ops.c:5159

static float8
circle_ar(CIRCLE *circle)
{
return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
}

src/include/utils/float.h:207

static inline float8
float8_mul(const float8 val1, const float8 val2)
{
float8 result;

result = val1 * val2;
if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
float_overflow_error();
...

Two float8_mul calls are inlined into one function. gcc keeps the first
copy's
overflow check and deletes the second's.

Disassembly of the shipped binary (circle_area; symbols are present in
.dynsym).
gcc lowers isinf(x) to |x| > DBL_MAX, with d30 = 0x7fefffffffffffff:

; inner multiply -- check intact
5540dc fmul d31, d29, d29 ; r*r
5540e0 fcmp d31, d30
5540e4 b.le 5540fc
5540e8 fabs d29, d29 ; |r| <- the !isinf(val1) test
5540ec fcmp d29, d30
5540f0 b.le 554154
554154 bl float_overflow_error ; raises

; outer multiply -- operand test gone
554104 adrp x0, 76c000
554108 ldr d29, [x0, #568] ; M_PI
55410c fmul d31, d31, d29 ; (r*r) * M_PI
554110 fcmp d31, d30
554114 b.le 554120
554118 mov x0, #0x7ff0000000000000 ; returns +Infinity
55411c b 55412c

Control reaches the outer multiply only via the b.le at 5540e4, i.e. only
when
r*r <= DBL_MAX, and M_PI is a finite constant. So
"!isinf(val1) && !isinf(val2)" is true on that path and
float_overflow_error()
must be called.

Building from an unmodified 18.3 tree (git tag stamp 62d6c7d) with gcc 14.2
and
the same CFLAGS reproduces it, so this is not specific to Debian's
packaging:

./configure --without-readline --without-zlib --without-icu \
CFLAGS="-g -O2 -fno-strict-aliasing -fwrapv
-fexcess-precision=standard"
make -C src/backend submake-generated-headers
make -C src/backend/utils/adt geo_ops.o
objdump -d geo_ops.o

circle_area then contains 3 fmul but only 1 call to float_overflow_error.
From
pristine source the outer check is removed entirely: there is no DBL_MAX
comparison after the second fmul at all, only the underflow test.

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message jian he 2026-08-01 09:49:22 Re: MERGE/SPLIT PARTITIONS issues/questions
Previous Message Zexin Li 2026-08-01 01:40:14 Re: BUG #19583: macaddr input accepts octet fields longer than 8 hex digits