This is an automated email from the ASF dual-hosted git repository.
yiguolei 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 287f5ca2de7 [Bug](function) fix mod function cause core dump (#37999)
287f5ca2de7 is described below
commit 287f5ca2de77a4b0a7c526b11d2d4892912c1ef6
Author: zhangstar333 <[email protected]>
AuthorDate: Sat Jul 20 16:00:09 2024 +0800
[Bug](function) fix mod function cause core dump (#37999)
## Proposed changes
as (-9223372036854775808 % -1) will cause coredump directly by fpe,
so check this case and throw exception.

<!--Describe your changes.-->
---
be/src/vec/functions/modulo.cpp | 18 ++++++++
.../sql_functions/math_functions/test_mod.out | 6 +++
.../sql_functions/math_functions/test_mod.groovy | 49 ++++++++++++++++++++++
3 files changed, 73 insertions(+)
diff --git a/be/src/vec/functions/modulo.cpp b/be/src/vec/functions/modulo.cpp
index 66376b66019..7a2dfc004ef 100644
--- a/be/src/vec/functions/modulo.cpp
+++ b/be/src/vec/functions/modulo.cpp
@@ -33,6 +33,20 @@
namespace doris::vectorized {
+template <typename A, typename B>
+inline void throw_if_division_leads_to_FPE(A a, B b) {
+ // http://avva.livejournal.com/2548306.html
+ // (-9223372036854775808 % -1) will cause coredump directly, so check this
case to throw exception, or maybe could return 0 as result
+ if constexpr (std::is_signed_v<A> && std::is_signed_v<B>) {
+ if (b == -1 && a == std::numeric_limits<A>::min()) {
+ throw Exception(ErrorCode::INVALID_ARGUMENT,
+ "Division of minimal signed number by minus one is
an undefined "
+ "behavior, {} % {}. ",
+ a, b);
+ }
+ }
+}
+
template <typename A, typename B>
struct ModuloImpl {
using ResultType = typename NumberTraits::ResultOfModulo<A, B>::Type;
@@ -51,6 +65,7 @@ struct ModuloImpl {
if constexpr (std::is_floating_point_v<ResultType>) {
c[i] = std::fmod((double)a[i], (double)b);
} else {
+ throw_if_division_leads_to_FPE(a[i], b);
c[i] = a[i] % b;
}
}
@@ -65,6 +80,7 @@ struct ModuloImpl {
if constexpr (std::is_floating_point_v<Result>) {
return std::fmod((double)a, (double)b);
} else {
+ throw_if_division_leads_to_FPE(a, b);
return a % b;
}
}
@@ -94,6 +110,7 @@ struct PModuloImpl {
if constexpr (std::is_floating_point_v<ResultType>) {
c[i] = std::fmod(std::fmod((double)a[i], (double)b) +
(double)b, double(b));
} else {
+ throw_if_division_leads_to_FPE(a[i], b);
c[i] = (a[i] % b + b) % b;
}
}
@@ -108,6 +125,7 @@ struct PModuloImpl {
if constexpr (std::is_floating_point_v<Result>) {
return std::fmod(std::fmod((double)a, (double)b) + (double)b,
(double)b);
} else {
+ throw_if_division_leads_to_FPE(a, b);
return (a % b + b) % b;
}
}
diff --git
a/regression-test/data/query_p0/sql_functions/math_functions/test_mod.out
b/regression-test/data/query_p0/sql_functions/math_functions/test_mod.out
new file mode 100644
index 00000000000..6e3ce6219de
--- /dev/null
+++ b/regression-test/data/query_p0/sql_functions/math_functions/test_mod.out
@@ -0,0 +1,6 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !sql --
+-2147483648 4 -1
+1 2 3
+5 -9223372036854775808 -1
+
diff --git
a/regression-test/suites/query_p0/sql_functions/math_functions/test_mod.groovy
b/regression-test/suites/query_p0/sql_functions/math_functions/test_mod.groovy
new file mode 100644
index 00000000000..027983ff749
--- /dev/null
+++
b/regression-test/suites/query_p0/sql_functions/math_functions/test_mod.groovy
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_mod") {
+ def tableName = "test_mod"
+ sql "set enable_fold_constant_by_be = false;"
+ sql """DROP TABLE IF EXISTS `test_mod`"""
+ sql """ CREATE TABLE `test_mod` (
+ `k1` int NULL COMMENT "用户id",
+ `k2` bigint COMMENT "数据灌入日期时间",
+ `k3` int COMMENT "数据灌入日期时间")
+ DUPLICATE KEY(`k1`) DISTRIBUTED BY HASH(`k1`)
+ PROPERTIES ( "replication_num" = "1" ); """
+
+ sql """ insert into `test_mod` values(1,2,3); """
+ sql """ insert into `test_mod` values(-2147483648,4,-1); """
+ sql """ insert into `test_mod` values(5,-9223372036854775808,-1); """
+
+ qt_sql """
+ SELECT * from test_mod order by 1;
+ """
+
+ test {
+ sql "select mod(-2147483648,-1); "
+ exception "Division of minimal signed number by minus one is an
undefined"
+ }
+ test {
+ sql "select mod(-9223372036854775808,-1); "
+ exception "Division of minimal signed number by minus one is an
undefined"
+ }
+ test {
+ sql "select pmod(-9223372036854775808,-1); "
+ exception "Division of minimal signed number by minus one is an
undefined"
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]