This is an automated email from the ASF dual-hosted git repository.

MuhammadTahaNaveed pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/age.git


The following commit(s) were added to refs/heads/master by this push:
     new d40b88b4 Raise division by zero for modulo with a zero divisor (#2571)
d40b88b4 is described below

commit d40b88b4bfc6d37b1a74700fc634fae8369441c3
Author: Fabiology <[email protected]>
AuthorDate: Sun Oct 11 02:19:23 2026 -0400

    Raise division by zero for modulo with a zero divisor (#2571)
    
    agtype_mod left the zero divisor unguarded, so an integer modulo trapped
    as SIGFPE and surfaced as "floating-point exception" (22P01) on x86_64,
    and silently returned the dividend on aarch64. The float paths returned
    NaN. agtype_div already checks for it, and so does PostgreSQL's int8mod.
    
    Closes 2514
    
    Co-authored-by: Fabiology <[email protected]>
---
 regress/expected/agtype.out        | 35 ++++++++++++++++++++++++++++++
 regress/sql/agtype.sql             | 20 +++++++++++++++++
 src/backend/utils/adt/agtype_ops.c | 44 ++++++++++++++++++++++++++++++++++++--
 3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/regress/expected/agtype.out b/regress/expected/agtype.out
index 0f4775b8..fa6af8dc 100644
--- a/regress/expected/agtype.out
+++ b/regress/expected/agtype.out
@@ -601,6 +601,41 @@ SELECT agtype_any_div('-1::numeric', 0);
 ERROR:  division by zero
 SELECT agtype_any_div('-1.0::numeric', 0);
 ERROR:  division by zero
+SELECT agtype_mod('1', '0');
+ERROR:  division by zero
+SELECT agtype_mod('1', '0.0');
+ERROR:  division by zero
+SELECT agtype_mod('1.0', '0');
+ERROR:  division by zero
+SELECT agtype_mod('1.0', '0.0');
+ERROR:  division by zero
+SELECT agtype_mod('1', '0::numeric');
+ERROR:  division by zero
+SELECT agtype_mod('1.0', '0::numeric');
+ERROR:  division by zero
+SELECT agtype_mod('1::numeric', '0');
+ERROR:  division by zero
+SELECT agtype_mod('1::numeric', '0.0');
+ERROR:  division by zero
+SELECT agtype_mod('1::numeric', '0::numeric');
+ERROR:  division by zero
+SELECT agtype_any_mod('1', 0);
+ERROR:  division by zero
+SELECT agtype_any_mod('1.0', 0);
+ERROR:  division by zero
+SELECT agtype_any_mod('-1::numeric', 0);
+ERROR:  division by zero
+SELECT agtype_any_mod('-1.0::numeric', 0);
+ERROR:  division by zero
+--
+-- Should get 0 - INT64_MIN % -1 is well defined
+--
+SELECT agtype_mod('-9223372036854775808', '-1');
+ agtype_mod 
+------------
+ 0
+(1 row)
+
 --
 -- Should get Infinity
 --
diff --git a/regress/sql/agtype.sql b/regress/sql/agtype.sql
index e13edb16..e351bbaf 100644
--- a/regress/sql/agtype.sql
+++ b/regress/sql/agtype.sql
@@ -199,6 +199,26 @@ SELECT agtype_any_div('1.0', 0);
 SELECT agtype_any_div('-1::numeric', 0);
 SELECT agtype_any_div('-1.0::numeric', 0);
 
+SELECT agtype_mod('1', '0');
+SELECT agtype_mod('1', '0.0');
+SELECT agtype_mod('1.0', '0');
+SELECT agtype_mod('1.0', '0.0');
+SELECT agtype_mod('1', '0::numeric');
+SELECT agtype_mod('1.0', '0::numeric');
+SELECT agtype_mod('1::numeric', '0');
+SELECT agtype_mod('1::numeric', '0.0');
+SELECT agtype_mod('1::numeric', '0::numeric');
+
+SELECT agtype_any_mod('1', 0);
+SELECT agtype_any_mod('1.0', 0);
+SELECT agtype_any_mod('-1::numeric', 0);
+SELECT agtype_any_mod('-1.0::numeric', 0);
+
+--
+-- Should get 0 - INT64_MIN % -1 is well defined
+--
+SELECT agtype_mod('-9223372036854775808', '-1');
+
 --
 -- Should get Infinity
 --
diff --git a/src/backend/utils/adt/agtype_ops.c 
b/src/backend/utils/adt/agtype_ops.c
index 000f410d..9a1c4033 100644
--- a/src/backend/utils/adt/agtype_ops.c
+++ b/src/backend/utils/adt/agtype_ops.c
@@ -912,24 +912,64 @@ Datum agtype_mod(PG_FUNCTION_ARGS)
 
     if (agtv_lhs->type == AGTV_INTEGER && agtv_rhs->type == AGTV_INTEGER)
     {
+        if (agtv_rhs->val.int_value == 0)
+        {
+            ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO),
+                            errmsg("division by zero")));
+            PG_RETURN_NULL();
+        }
+
         agtv_result.type = AGTV_INTEGER;
-        agtv_result.val.int_value = agtv_lhs->val.int_value %
-                                    agtv_rhs->val.int_value;
+
+        /*
+         * INT64_MIN % -1 is zero but overflows the quotient, which traps on
+         * some platforms. int8mod special cases it the same way.
+         */
+        if (agtv_rhs->val.int_value == -1)
+        {
+            agtv_result.val.int_value = 0;
+        }
+        else
+        {
+            agtv_result.val.int_value = agtv_lhs->val.int_value %
+                                        agtv_rhs->val.int_value;
+        }
     }
     else if (agtv_lhs->type == AGTV_FLOAT && agtv_rhs->type == AGTV_FLOAT)
     {
+        if (agtv_rhs->val.float_value == 0)
+        {
+            ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO),
+                            errmsg("division by zero")));
+            PG_RETURN_NULL();
+        }
+
         agtv_result.type = AGTV_FLOAT;
         agtv_result.val.float_value = fmod(agtv_lhs->val.float_value,
                                            agtv_rhs->val.float_value);
     }
     else if (agtv_lhs->type == AGTV_FLOAT && agtv_rhs->type == AGTV_INTEGER)
     {
+        if (agtv_rhs->val.int_value == 0)
+        {
+            ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO),
+                            errmsg("division by zero")));
+            PG_RETURN_NULL();
+        }
+
         agtv_result.type = AGTV_FLOAT;
         agtv_result.val.float_value = fmod(agtv_lhs->val.float_value,
                                            agtv_rhs->val.int_value);
     }
     else if (agtv_lhs->type == AGTV_INTEGER && agtv_rhs->type == AGTV_FLOAT)
     {
+        if (agtv_rhs->val.float_value == 0)
+        {
+            ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO),
+                            errmsg("division by zero")));
+            PG_RETURN_NULL();
+        }
+
         agtv_result.type = AGTV_FLOAT;
         agtv_result.val.float_value = fmod(agtv_lhs->val.int_value,
                                            agtv_rhs->val.float_value);

Reply via email to