Commit 328edf85 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-21977 main.func_math fails due to undefined behaviour

The problem happened in these line:

uval0= (ulonglong) (val0_negative ? -val0 : val0);
uval1= (ulonglong) (val1_negative ? -val1 : val1);

return check_integer_overflow(val0_negative ? -(longlong) res : res,
                              !val0_negative);

when unary minus was performed on -9223372036854775808.
This behavior is undefined in C/C++.
parent 5c1ed707
...@@ -946,5 +946,53 @@ STDDEV_SAMP(a) ...@@ -946,5 +946,53 @@ STDDEV_SAMP(a)
NULL NULL
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-21977 main.func_math fails due to undefined behaviour
#
SELECT 9223372036854775808 DIV 1;
9223372036854775808 DIV 1
9223372036854775808
SELECT 9223372036854775808 DIV -1;
ERROR 22003: BIGINT UNSIGNED value is out of range in '(9223372036854775808 DIV -(1))'
SELECT -9223372036854775808 DIV 1;
ERROR 22003: BIGINT value is out of range in '(-(9223372036854775808) DIV 1)'
SELECT -9223372036854775808 DIV -1;
ERROR 22003: BIGINT value is out of range in '(-(9223372036854775808) DIV -(1))'
SELECT 9223372036854775808 MOD 1;
9223372036854775808 MOD 1
0
SELECT 9223372036854775808 MOD -1;
9223372036854775808 MOD -1
0
SELECT -9223372036854775808 MOD 1;
-9223372036854775808 MOD 1
0
SELECT -9223372036854775808 MOD -1;
-9223372036854775808 MOD -1
0
SELECT 1 MOD 9223372036854775808;
1 MOD 9223372036854775808
1
SELECT -1 MOD 9223372036854775808;
-1 MOD 9223372036854775808
-1
SELECT 1 MOD -9223372036854775808;
1 MOD -9223372036854775808
1
SELECT -1 MOD -9223372036854775808;
-1 MOD -9223372036854775808
-1
SELECT 9223372036854775808 MOD 9223372036854775808;
9223372036854775808 MOD 9223372036854775808
0
SELECT 9223372036854775808 MOD -9223372036854775808;
9223372036854775808 MOD -9223372036854775808
0
SELECT -9223372036854775808 MOD 9223372036854775808;
-9223372036854775808 MOD 9223372036854775808
0
SELECT -9223372036854775808 MOD -9223372036854775808;
-9223372036854775808 MOD -9223372036854775808
0
#
# End of 10.1 tests # End of 10.1 tests
# #
...@@ -692,6 +692,35 @@ SELECT STDDEV_SAMP(a) FROM t1; ...@@ -692,6 +692,35 @@ SELECT STDDEV_SAMP(a) FROM t1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-21977 main.func_math fails due to undefined behaviour
--echo #
SELECT 9223372036854775808 DIV 1;
--error ER_DATA_OUT_OF_RANGE
SELECT 9223372036854775808 DIV -1;
--error ER_DATA_OUT_OF_RANGE
SELECT -9223372036854775808 DIV 1;
--error ER_DATA_OUT_OF_RANGE
SELECT -9223372036854775808 DIV -1;
SELECT 9223372036854775808 MOD 1;
SELECT 9223372036854775808 MOD -1;
SELECT -9223372036854775808 MOD 1;
SELECT -9223372036854775808 MOD -1;
SELECT 1 MOD 9223372036854775808;
SELECT -1 MOD 9223372036854775808;
SELECT 1 MOD -9223372036854775808;
SELECT -1 MOD -9223372036854775808;
SELECT 9223372036854775808 MOD 9223372036854775808;
SELECT 9223372036854775808 MOD -9223372036854775808;
SELECT -9223372036854775808 MOD 9223372036854775808;
SELECT -9223372036854775808 MOD -9223372036854775808;
--echo # --echo #
--echo # End of 10.1 tests --echo # End of 10.1 tests
--echo # --echo #
...@@ -1834,11 +1834,9 @@ longlong Item_func_int_div::val_int() ...@@ -1834,11 +1834,9 @@ longlong Item_func_int_div::val_int()
raise_integer_overflow(); raise_integer_overflow();
return res; return res;
} }
longlong val0=args[0]->val_int(); Longlong_hybrid val0= args[0]->to_longlong_hybrid();
longlong val1=args[1]->val_int(); Longlong_hybrid val1= args[1]->to_longlong_hybrid();
bool val0_negative, val1_negative, res_negative;
ulonglong uval0, uval1, res;
if ((null_value= (args[0]->null_value || args[1]->null_value))) if ((null_value= (args[0]->null_value || args[1]->null_value)))
return 0; return 0;
if (val1 == 0) if (val1 == 0)
...@@ -1847,12 +1845,8 @@ longlong Item_func_int_div::val_int() ...@@ -1847,12 +1845,8 @@ longlong Item_func_int_div::val_int()
return 0; return 0;
} }
val0_negative= !args[0]->unsigned_flag && val0 < 0; bool res_negative= val0.neg() != val1.neg();
val1_negative= !args[1]->unsigned_flag && val1 < 0; ulonglong res= val0.abs() / val1.abs();
res_negative= val0_negative != val1_negative;
uval0= (ulonglong) (val0_negative ? -val0 : val0);
uval1= (ulonglong) (val1_negative ? -val1 : val1);
res= uval0 / uval1;
if (res_negative) if (res_negative)
{ {
if (res > (ulonglong) LONGLONG_MAX) if (res > (ulonglong) LONGLONG_MAX)
...@@ -1880,11 +1874,8 @@ void Item_func_int_div::fix_length_and_dec() ...@@ -1880,11 +1874,8 @@ void Item_func_int_div::fix_length_and_dec()
longlong Item_func_mod::int_op() longlong Item_func_mod::int_op()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
longlong val0= args[0]->val_int(); Longlong_hybrid val0= args[0]->to_longlong_hybrid();
longlong val1= args[1]->val_int(); Longlong_hybrid val1= args[1]->to_longlong_hybrid();
bool val0_negative, val1_negative;
ulonglong uval0, uval1;
ulonglong res;
if ((null_value= args[0]->null_value || args[1]->null_value)) if ((null_value= args[0]->null_value || args[1]->null_value))
return 0; /* purecov: inspected */ return 0; /* purecov: inspected */
...@@ -1899,13 +1890,9 @@ longlong Item_func_mod::int_op() ...@@ -1899,13 +1890,9 @@ longlong Item_func_mod::int_op()
LONGLONG_MIN by -1 generates SIGFPE, we calculate using unsigned values and LONGLONG_MIN by -1 generates SIGFPE, we calculate using unsigned values and
then adjust the sign appropriately. then adjust the sign appropriately.
*/ */
val0_negative= !args[0]->unsigned_flag && val0 < 0; ulonglong res= val0.abs() % val1.abs();
val1_negative= !args[1]->unsigned_flag && val1 < 0; return check_integer_overflow(val0.neg() ? -(longlong) res : res,
uval0= (ulonglong) (val0_negative ? -val0 : val0); !val0.neg());
uval1= (ulonglong) (val1_negative ? -val1 : val1);
res= uval0 % uval1;
return check_integer_overflow(val0_negative ? -(longlong) res : res,
!val0_negative);
} }
double Item_func_mod::real_op() double Item_func_mod::real_op()
......
...@@ -67,6 +67,26 @@ class Longlong_hybrid ...@@ -67,6 +67,26 @@ class Longlong_hybrid
*/ */
return cmp_signed(other); return cmp_signed(other);
} }
bool operator==(const Longlong_hybrid &nr) const
{
return cmp(nr) == 0;
}
bool operator==(ulonglong nr) const
{
return cmp(Longlong_hybrid((longlong) nr, true)) == 0;
}
bool operator==(uint nr) const
{
return cmp(Longlong_hybrid((longlong) nr, true)) == 0;
}
bool operator==(longlong nr) const
{
return cmp(Longlong_hybrid(nr, false)) == 0;
}
bool operator==(int nr) const
{
return cmp(Longlong_hybrid(nr, false)) == 0;
}
}; };
#endif // SQL_TYPE_INT_INCLUDED #endif // SQL_TYPE_INT_INCLUDED
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment