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

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


The following commit(s) were added to refs/heads/master by this push:
     new b054f57c5f2 [fix](be) prevent SIGFPE in int_divide for signed min 
value (#64828)
b054f57c5f2 is described below

commit b054f57c5f20ff87e0de46d930aadd4425669b8b
Author: Mryange <[email protected]>
AuthorDate: Mon Jun 29 16:56:56 2026 +0800

    [fix](be) prevent SIGFPE in int_divide for signed min value (#64828)
    
    ### What problem does this PR solve?
    
    `BIGINT_MIN DIV -1` can trigger signed integer overflow in BE
    `int_divide` and terminate the backend with `SIGFPE`. Root cause:
    `DivideIntegralImpl` only handled division by zero, but did not guard
    the undefined signed case where the minimal signed integer is divided by
    `-1`. This change follows the existing `mod`/`pmod` behavior and returns
    `INVALID_ARGUMENT` before executing the unsafe division. The guard
    covers const/const, vector/const, const/vector, and vector/vector paths.
    
    
    https://godbolt.org/z/YPq9W581e
    
    ### Release note
    
    None
---
 be/src/exprs/function/int_div.cpp                  | 30 +++++++-
 .../exprs/function/function_arithmetic_test.cpp    | 87 ++++++++++++++++++++++
 2 files changed, 115 insertions(+), 2 deletions(-)

diff --git a/be/src/exprs/function/int_div.cpp 
b/be/src/exprs/function/int_div.cpp
index a096f23d693..747cf27f47c 100644
--- a/be/src/exprs/function/int_div.cpp
+++ b/be/src/exprs/function/int_div.cpp
@@ -20,6 +20,7 @@
 
 #include <libdivide.h>
 
+#include <limits>
 #include <utility>
 
 #include "core/data_type/data_type_number.h"
@@ -114,12 +115,21 @@ struct DivideIntegralImpl {
     using Arg = typename PrimitiveTypeTraits<Type>::CppType;
     using ColumnType = typename PrimitiveTypeTraits<Type>::ColumnType;
     static constexpr PrimitiveType ResultType = Type;
+    static constexpr bool is_signed_integer = std::is_signed_v<Arg> || 
std::is_same_v<Arg, Int128>;
 
     static DataTypes get_variadic_argument_types() {
         return {std::make_shared<typename 
PrimitiveTypeTraits<Type>::DataType>(),
                 std::make_shared<typename 
PrimitiveTypeTraits<Type>::DataType>()};
     }
 
+    static bool division_leads_to_fpe(Arg a, Arg b) {
+        if constexpr (is_signed_integer) {
+            return b == -1 && a == std::numeric_limits<Arg>::min();
+        } else {
+            return false;
+        }
+    }
+
     static void apply(const typename ColumnType::Container& a, Arg b,
                       typename 
PrimitiveTypeTraits<ResultType>::ColumnType::Container& c,
                       PaddedPODArray<UInt8>& null_map) {
@@ -128,6 +138,19 @@ struct DivideIntegralImpl {
         memset(null_map.data(), is_null, size);
 
         if (!is_null) {
+            if constexpr (is_signed_integer) {
+                if (b == -1) {
+                    for (size_t i = 0; i < size; i++) {
+                        null_map[i] = division_leads_to_fpe(a[i], b);
+                        if (!null_map[i]) {
+                            c[i] = typename 
PrimitiveTypeTraits<ResultType>::CppType(a[i] / b);
+                        } else {
+                            c[i] = {};
+                        }
+                    }
+                    return;
+                }
+            }
             if constexpr (!std::is_floating_point_v<Arg> && 
!std::is_same_v<Arg, Int128> &&
                           !std::is_same_v<Arg, Int8> && !std::is_same_v<Arg, 
UInt8>) {
                 const auto divider = libdivide::divider<Arg>(Arg(b));
@@ -144,8 +167,11 @@ struct DivideIntegralImpl {
 
     static inline typename PrimitiveTypeTraits<ResultType>::CppType apply(Arg 
a, Arg b,
                                                                           
UInt8& is_null) {
-        is_null = b == 0;
-        return typename PrimitiveTypeTraits<ResultType>::CppType(a / (b + 
is_null));
+        is_null = b == 0 || division_leads_to_fpe(a, b);
+        if (is_null) {
+            return {};
+        }
+        return typename PrimitiveTypeTraits<ResultType>::CppType(a / b);
     }
 
     static ColumnPtr constant_constant(Arg a, Arg b) {
diff --git a/be/test/exprs/function/function_arithmetic_test.cpp 
b/be/test/exprs/function/function_arithmetic_test.cpp
index bf40fa7bf55..09c66ba9bf8 100644
--- a/be/test/exprs/function/function_arithmetic_test.cpp
+++ b/be/test/exprs/function/function_arithmetic_test.cpp
@@ -18,6 +18,7 @@
 #include <stdint.h>
 
 #include <iomanip>
+#include <limits>
 #include <string>
 #include <vector>
 
@@ -53,6 +54,92 @@ TEST(function_arithmetic_test, 
function_arithmetic_divide_test) {
     }
 }
 
+TEST(function_arithmetic_test, 
function_arithmetic_int_divide_min_signed_by_minus_one_test) {
+    std::string func_name = "int_divide";
+    const auto min_int8 = std::numeric_limits<int8_t>::min();
+    const auto min_int16 = std::numeric_limits<int16_t>::min();
+    const auto min_int32 = std::numeric_limits<int32_t>::min();
+    const auto min_int64 = std::numeric_limits<int64_t>::min();
+    const auto min_int128 = std::numeric_limits<Int128>::min();
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_TINYINT, 
PrimitiveType::TYPE_TINYINT};
+        DataSet data_set = {{{int8_t {1}, int8_t {-1}}, int8_t {-1}},
+                            {{min_int8, int8_t {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt8, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_SMALLINT, 
PrimitiveType::TYPE_SMALLINT};
+        DataSet data_set = {{{int16_t {1}, int16_t {-1}}, int16_t {-1}},
+                            {{min_int16, int16_t {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt16, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_INT, 
PrimitiveType::TYPE_INT};
+        DataSet data_set = {{{int32_t {1}, int32_t {-1}}, int32_t {-1}},
+                            {{min_int32, int32_t {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt32, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {Consted {PrimitiveType::TYPE_BIGINT},
+                                    Consted {PrimitiveType::TYPE_BIGINT}};
+        DataSet data_set = {{{min_int64, int64_t {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt64, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_BIGINT,
+                                    Consted {PrimitiveType::TYPE_BIGINT}};
+        DataSet data_set = {{{min_int64, int64_t {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt64, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {Consted {PrimitiveType::TYPE_BIGINT},
+                                    PrimitiveType::TYPE_BIGINT};
+        DataSet data_set = {{{min_int64, int64_t {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt64, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_BIGINT, 
PrimitiveType::TYPE_BIGINT};
+        DataSet data_set = {{{int64_t {1}, int64_t {-1}}, int64_t {-1}},
+                            {{min_int64, int64_t {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt64, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {Consted {PrimitiveType::TYPE_LARGEINT},
+                                    Consted {PrimitiveType::TYPE_LARGEINT}};
+        DataSet data_set = {{{min_int128, Int128 {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt128, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_LARGEINT,
+                                    Consted {PrimitiveType::TYPE_LARGEINT}};
+        DataSet data_set = {{{min_int128, Int128 {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt128, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {Consted {PrimitiveType::TYPE_LARGEINT},
+                                    PrimitiveType::TYPE_LARGEINT};
+        DataSet data_set = {{{min_int128, Int128 {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt128, true>(func_name, 
input_types, data_set));
+    }
+
+    {
+        InputTypeSet input_types = {PrimitiveType::TYPE_LARGEINT, 
PrimitiveType::TYPE_LARGEINT};
+        DataSet data_set = {{{Int128 {1}, Int128 {-1}}, Int128 {-1}},
+                            {{min_int128, Int128 {-1}}, Null()}};
+        static_cast<void>(check_function<DataTypeInt128, true>(func_name, 
input_types, data_set));
+    }
+}
+
 TEST(function_arithmetic_test, bitnot_test) {
     std::string func_name = "bitnot";
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to