This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.1 by this push:
new 572bf1333d5 branch-4.1: [fix](be) prevent SIGFPE in int_divide for
signed min value #64828 (#64948)
572bf1333d5 is described below
commit 572bf1333d5461dc1b4b8806232bcb53590a5d7a
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Jun 30 12:23:57 2026 +0800
branch-4.1: [fix](be) prevent SIGFPE in int_divide for signed min value
#64828 (#64948)
Cherry-picked from #64828
Co-authored-by: Mryange <[email protected]>
---
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 923c0d12a57..52229a7a865 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"
@@ -112,12 +113,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) {
@@ -126,6 +136,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));
@@ -142,8 +165,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]