From c5a6b65c7589959f73be280363583ad67667aa52 Mon Sep 17 00:00:00 2001 From: Andrey Rachitskiy Date: Tue, 4 Aug 2026 22:03:49 +0500 Subject: [PATCH] Keep float8_mul overflow checks alive under gcc 13+ gcc 13+ jump threading can drop the isinf() overflow test in an inlined float8_mul() when both operands are proven finite, as in circle_ar() after r*r with constant M_PI. Report via non-noreturn float_*_error_ext() helpers so the check is retained. Add a geometry regress for area(circle) with radius 1e154. Bug: #19593 Author: Andrey Rachitskiy Reported-by: Michael Malis Discussion: https://www.postgresql.org/message-id/19593-d80bd21f90d32234%40postgresql.org --- src/backend/utils/adt/float.c | 27 +++++++++++++++++++++++++++ src/include/utils/float.h | 10 ++++++++-- src/test/regress/expected/geometry.out | 3 +++ src/test/regress/sql/geometry.sql | 3 +++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index adb8c74cdde..7045c016f96 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -106,2 +106,26 @@ float_zero_divide_error(void) +/* + * Non-noreturn helpers for float8_mul(). + * + * float_*_error() is noreturn. Calling it directly from inlined + * float8_mul() lets gcc 13+ jump threading drop a live isinf() check + * after proving both operands finite. Returning through these wrappers + * changes the CFG enough to keep that check. The return 0.0 is never + * executed (ereport does not return). It exists so the compiler sees an + * ordinary float8-returning call rather than a noreturn one. + */ +float8 +float_overflow_error_ext(void) +{ + float_overflow_error(); + return 0.0; +} + +float8 +float_underflow_error_ext(void) +{ + float_underflow_error(); + return 0.0; +} + diff --git a/src/include/utils/float.h b/src/include/utils/float.h index fcf7bd581bd..313d4848b96 100644 --- a/src/include/utils/float.h +++ b/src/include/utils/float.h @@ -43,1 +43,3 @@ +extern float8 float_overflow_error_ext(void); +extern float8 float_underflow_error_ext(void); extern int is_infinite(float8 val); @@ -205,2 +207,6 @@ float4_mul(const float4 val1, const float4 val2) +/* + * Report via non-noreturn helpers. gcc 13+ jump threading may otherwise + * drop the isinf() check when both operands are proven finite. + */ static inline float8 @@ -212,5 +218,5 @@ float8_mul(const float8 val1, const float8 val2) if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) - float_overflow_error(); + return float_overflow_error_ext(); if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0) - float_underflow_error(); + return float_underflow_error_ext(); diff --git a/src/test/regress/expected/geometry.out b/src/test/regress/expected/geometry.out index 4bb1679157d..8ee277431ec 100644 --- a/src/test/regress/expected/geometry.out +++ b/src/test/regress/expected/geometry.out @@ -5137,2 +5137,5 @@ SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0, ERROR: division by zero +-- Overflow for radius 1e154 +SELECT area(circle '<(0,0),1e154>'); +ERROR: value out of range: overflow -- Distance to polygon diff --git a/src/test/regress/sql/geometry.sql b/src/test/regress/sql/geometry.sql index bbb6acd4555..081f2d160cd 100644 --- a/src/test/regress/sql/geometry.sql +++ b/src/test/regress/sql/geometry.sql @@ -510,2 +510,5 @@ SELECT c.f1, p.f1, c.f1 / p.f1 FROM CIRCLE_TBL c, POINT_TBL p WHERE p.f1 ~= '(0, +-- Overflow for radius 1e154 +SELECT area(circle '<(0,0),1e154>'); + -- Distance to polygon -- 2.53.0