From 25879b97cff622cae8a56dddd34a1a79738a1993 Mon Sep 17 00:00:00 2001
From: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Date: Wed, 5 Aug 2026 09:02:47 +0500
Subject: [PATCH] Keep float8 overflow checks alive under gcc 13+

gcc 13+ jump threading can drop an isinf() overflow test in inlined
float8_{pl,mi,mul,div} when both operands are proven finite, for example
in circle_ar() after r*r with constant M_PI, or in nested pl(mul,mul).
Report via non-noreturn float_*_error_ext() helpers so the checks are
retained.  float4_* are left unchanged.  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          | 24 ++++++++++++++++++++++++
 src/include/utils/float.h              | 19 +++++++++++++------
 src/test/regress/expected/geometry.out |  3 +++
 src/test/regress/sql/geometry.sql      |  3 +++
 4 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index adb8c74cdde..c9bcc4da786 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_{pl,mi,mul,div}.
+ *
+ * float_*_error() is noreturn.  Calling it directly from those inlined
+ * helpers 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..a34a8453e21 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);
@@ -155,2 +157,7 @@ float4_pl(const float4 val1, const float4 val2)
 
+/*
+ * float8_{pl,mi,mul,div} report via non-noreturn helpers.  gcc 13+ jump
+ * threading may otherwise drop an isinf() check when both operands are
+ * proven finite (e.g. nested helpers after an earlier overflow check).
+ */
 static inline float8
@@ -162,3 +169,3 @@ float8_pl(const float8 val1, const float8 val2)
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+		return float_overflow_error_ext();
 
@@ -186,3 +193,3 @@ float8_mi(const float8 val1, const float8 val2)
 	if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2))
-		float_overflow_error();
+		return float_overflow_error_ext();
 
@@ -212,5 +219,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();
 
@@ -244,5 +251,5 @@ float8_div(const float8 val1, const float8 val2)
 	if (unlikely(isinf(result)) && !isinf(val1))
-		float_overflow_error();
+		return float_overflow_error_ext();
 	if (unlikely(result == 0.0) && val1 != 0.0 && !isinf(val2))
-		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

