Commit 3141a68b authored by Alexander Barkov's avatar Alexander Barkov

MDEV-33534 UBSAN: Negation of -X cannot be represented in type 'long long...

MDEV-33534 UBSAN: Negation of -X cannot be represented in type 'long long int'; cast to an unsigned type to negate this value to itself in my_double_round from sql/item_func.cc|

The negation in this line:
  ulonglong abs_dec= dec_negative ? -dec : dec;
did not take into account that 'dec' can be the smallest possible
signed negative value -9223372036854775808. Its negation is
an operation with an undefined behavior.

Fixing the code to use Longlong_hybrid, which implements a safe
method to get an absolute value.
parent 3d417476
...@@ -3617,5 +3617,20 @@ SELECT CRC32(ExtractValue('<a><b/></a>', '/a/b')) AS f; ...@@ -3617,5 +3617,20 @@ SELECT CRC32(ExtractValue('<a><b/></a>', '/a/b')) AS f;
f f
0 0
# #
# MDEV-33534 UBSAN: Negation of -X cannot be represented in type 'long long int'; cast to an unsigned type to negate this value to itself in my_double_round from sql/item_func.cc|
#
SELECT TRUNCATE(EXP(-1.e-2),-1.e+30) AS c1;
c1
0
SELECT (TRUNCATE(EXP(-1.e-2),-1.e+30) % RADIANS(-1)) AS c1;
c1
0
SELECT (TRUNCATE(EXP(-1.e-2),-1.e+30) % RADIANS(-1)) * (LAST_DAY('1-03-30 1:29:12') MOD 1 + COS(-1)) AS c1;
c1
0
SELECT(ASIN(-1)+ LN(-1)) % (ATAN(-1) MOD FLOOR(1)) * (TRUNCATE(EXP(-1.e-2),-1.e+30) % RADIANS(-1)) * (LAST_DAY('1-03-30 1:29:12') MOD 1 + COS(-1)) AS c1;
c1
NULL
#
# End of 10.5 tests # End of 10.5 tests
# #
...@@ -1929,6 +1929,16 @@ DROP TABLE t2, t1; ...@@ -1929,6 +1929,16 @@ DROP TABLE t2, t1;
SELECT CRC32(ExtractValue('<a><b/></a>', '/a/b')) AS f; SELECT CRC32(ExtractValue('<a><b/></a>', '/a/b')) AS f;
--echo #
--echo # MDEV-33534 UBSAN: Negation of -X cannot be represented in type 'long long int'; cast to an unsigned type to negate this value to itself in my_double_round from sql/item_func.cc|
--echo #
SELECT TRUNCATE(EXP(-1.e-2),-1.e+30) AS c1;
SELECT (TRUNCATE(EXP(-1.e-2),-1.e+30) % RADIANS(-1)) AS c1;
SELECT (TRUNCATE(EXP(-1.e-2),-1.e+30) % RADIANS(-1)) * (LAST_DAY('1-03-30 1:29:12') MOD 1 + COS(-1)) AS c1;
SELECT(ASIN(-1)+ LN(-1)) % (ATAN(-1) MOD FLOOR(1)) * (TRUNCATE(EXP(-1.e-2),-1.e+30) % RADIANS(-1)) * (LAST_DAY('1-03-30 1:29:12') MOD 1 + COS(-1)) AS c1;
--echo # --echo #
--echo # End of 10.5 tests --echo # End of 10.5 tests
--echo # --echo #
...@@ -2638,12 +2638,12 @@ void Item_func_round::fix_arg_hex_hybrid() ...@@ -2638,12 +2638,12 @@ void Item_func_round::fix_arg_hex_hybrid()
} }
double my_double_round(double value, longlong dec, bool dec_unsigned, double my_double_round(double value, longlong dec_value, bool dec_unsigned,
bool truncate) bool truncate)
{ {
double tmp; double tmp;
bool dec_negative= (dec < 0) && !dec_unsigned; const Longlong_hybrid dec(dec_value, dec_unsigned);
ulonglong abs_dec= dec_negative ? -dec : dec; const ulonglong abs_dec= dec.abs();
/* /*
tmp2 is here to avoid return the value with 80 bit precision tmp2 is here to avoid return the value with 80 bit precision
This will fix that the test round(0.1,1) = round(0.1,1) is true This will fix that the test round(0.1,1) = round(0.1,1) is true
...@@ -2658,22 +2658,24 @@ double my_double_round(double value, longlong dec, bool dec_unsigned, ...@@ -2658,22 +2658,24 @@ double my_double_round(double value, longlong dec, bool dec_unsigned,
volatile double value_div_tmp= value / tmp; volatile double value_div_tmp= value / tmp;
volatile double value_mul_tmp= value * tmp; volatile double value_mul_tmp= value * tmp;
if (!dec_negative && std::isinf(tmp)) // "dec" is too large positive number if (!dec.neg() && std::isinf(tmp)) // "dec" is a too large positive number
return value; return value;
if (dec_negative && std::isinf(tmp)) if (dec.neg() && std::isinf(tmp)) // "dec" is a too small negative number
tmp2= 0.0; return 0.0;
else if (!dec_negative && std::isinf(value_mul_tmp))
// Handle "dec" with a reasonably small absolute value
if (!dec.neg() && std::isinf(value_mul_tmp))
tmp2= value; tmp2= value;
else if (truncate) else if (truncate)
{ {
if (value >= 0.0) if (value >= 0.0)
tmp2= dec < 0 ? floor(value_div_tmp) * tmp : floor(value_mul_tmp) / tmp; tmp2= dec.neg() ? floor(value_div_tmp) * tmp : floor(value_mul_tmp) / tmp;
else else
tmp2= dec < 0 ? ceil(value_div_tmp) * tmp : ceil(value_mul_tmp) / tmp; tmp2= dec.neg() ? ceil(value_div_tmp) * tmp : ceil(value_mul_tmp) / tmp;
} }
else else
tmp2=dec < 0 ? rint(value_div_tmp) * tmp : rint(value_mul_tmp) / tmp; tmp2=dec.neg() ? rint(value_div_tmp) * tmp : rint(value_mul_tmp) / tmp;
return tmp2; return tmp2;
} }
......
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