From c5a6b65c7589959f73be280363583ad67667aa52 Mon Sep 17 00:00:00 2001
From: Andrey Rachitskiy <pl0h0yp1@gmail.com>
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 <pl0h0yp1@gmail.com>
Reported-by: Michael Malis <malis@pgrust.com>
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

