Skip to content

Commit 6eda0af

Browse files
committed
MDEV-28374 UBSAN signed integer overflow PROCEDURE ANALYSE
PROCEDURE ANALYSE returns a Std (Standard deviation) which involves the sum of squares, which can exceed the longlong datatypes. Adjust the sum_sqr and sum value to double to acocunt that its only used in a double context and precision isn't required. Reviewed by: Alexander Barkov
1 parent a9a93c4 commit 6eda0af

6 files changed

Lines changed: 251 additions & 33 deletions

File tree

mysql-test/main/func_analyse.result

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,105 @@ DROP TABLE t;
257257
#
258258
# End of 10.5 tests
259259
#
260+
#
261+
# MDEV-28374 UBSAN signed integer overflow PROCEDURE ANALYSE
262+
#
263+
SET sql_mode='';
264+
CREATE TABLE t (a BIGINT);
265+
INSERT INTO t VALUES ('10000000000000'),('10000000000000');
266+
SELECT * FROM t PROCEDURE ANALYSE();
267+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
268+
test.t.a 10000000000000 10000000000000 14 14 0 0 10000000000000.0000 0.0000 ENUM('10000000000000') NOT NULL
269+
DROP TABLE t;
270+
CREATE TABLE t (a BIGINT UNSIGNED);
271+
INSERT INTO t VALUES ('18446744073709551615'),('18446744073709551615');
272+
SELECT * FROM t PROCEDURE ANALYSE();
273+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
274+
test.t.a 18446744073709551615 18446744073709551615 20 20 0 0 18446744073709552000.0000 0.0000 ENUM('18446744073709551615') NOT NULL
275+
DROP TABLE t;
276+
CREATE TABLE t (a BIGINT,KEY a USING BTREE (a));
277+
INSERT INTO t VALUES (0),('1'),('1'),('1'),('1'),('00010101'),('99991231'),('00101000000'),('691231000000'),('700101000000'),('991231235959'),('10000101000000'),('99991231235959'),('20030100000000'),('20030000000000');
278+
SELECT * FROM t PROCEDURE ANALYSE();
279+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
280+
test.t.a 0 99991231235959 1 14 1 0 10162279764883.6000 24971351159406.2300 ENUM('0','1','10101','99991231','101000000','691231000000','700101000000','991231235959','10000101000000','20030000000000','20030100000000','99991231235959') NOT NULL
281+
DROP TABLE t;
282+
CREATE TABLE t (c BIGINT,c2 DATE,c3 BLOB,KEY(c)) ENGINE=InnoDB;
283+
INSERT INTO t VALUES (-1.e+308,1,1);
284+
Warnings:
285+
Warning 1264 Out of range value for column 'c' at row 1
286+
Warning 1265 Data truncated for column 'c2' at row 1
287+
SELECT * FROM t PROCEDURE ANALYSE();
288+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
289+
test.t.c -9223372036854775808 -9223372036854775808 20 20 0 0 -9223372036854776000.0000 0.0000 ENUM('-9223372036854775808') NOT NULL
290+
test.t.c2 0000-00-00 0000-00-00 10 10 0 0 10.0000 NULL ENUM('0000-00-00') NOT NULL
291+
test.t.c3 1 1 1 1 0 0 1.0000 NULL ENUM('1') NOT NULL
292+
DROP TABLE t;
293+
CREATE TABLE t (c INT) ENGINE=InnoDB UNION=(t,t2) INSERT_METHOD=LAST;
294+
CREATE TABLE t3 LIKE t;
295+
INSERT INTO t VALUES (1),(2),(-685113344),(0);
296+
INSERT INTO t3 SELECT * FROM t;
297+
INSERT INTO t SELECT * FROM t;
298+
INSERT INTO t SELECT * FROM t;
299+
INSERT INTO t3 SELECT * FROM t;
300+
SELECT * FROM t3 PROCEDURE ANALYSE();
301+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
302+
test.t3.c -685113344 2 1 10 5 0 -171278335.2500 296662780.6209 ENUM('-685113344','0','1','2') NOT NULL
303+
DROP TABLE t, t3;
304+
CREATE TABLE t (c INT) ENGINE=InnoDB UNION=(t,t2) INSERT_METHOD=LAST;
305+
INSERT INTO t VALUES (1);
306+
INSERT INTO t VALUES (0xA9BD);
307+
INSERT INTO t (c) VALUES (ADDTIME(NOW(),1));
308+
Warnings:
309+
Warning 1264 Out of range value for column 'c' at row 1
310+
CREATE TABLE c AS SELECT 1 A;
311+
SELECT * FROM t a,c,t b PROCEDURE ANALYSE();
312+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
313+
test.a.c 1 2147483647 1 10 0 0 715842367.0000 1012323257.4700 ENUM('1','43453','2147483647') NOT NULL
314+
test.c.A 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL
315+
test.b.c 1 2147483647 1 10 0 0 715842367.0000 1012323257.4700 ENUM('1','43453','2147483647') NOT NULL
316+
DROP TABLE t, c;
317+
CREATE TABLE t (c BIGINT);
318+
INSERT INTO t VALUES (1000000000000000);
319+
SELECT * FROM t PROCEDURE ANALYSE(0,0);
320+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
321+
test.t.c 1000000000000000 1000000000000000 16 16 0 0 1000000000000000.0000 0.0000 BIGINT(16) UNSIGNED NOT NULL
322+
DROP TABLE t;
323+
CREATE SEQUENCE t CACHE=1 MAXVALUE=0 INCREMENT=-1;
324+
SELECT * FROM t PROCEDURE ANALYSE();
325+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
326+
test.t.next_not_cached_value 0 0 1 1 1 0 0.0000 0.0000 ENUM('0') NOT NULL
327+
test.t.minimum_value -9223372036854775807 -9223372036854775807 20 20 0 0 -9223372036854776000.0000 0.0000 ENUM('-9223372036854775807') NOT NULL
328+
test.t.maximum_value 0 0 1 1 1 0 0.0000 0.0000 ENUM('0') NOT NULL
329+
test.t.start_value 0 0 1 1 1 0 0.0000 0.0000 ENUM('0') NOT NULL
330+
test.t.increment -1 -1 2 2 0 0 -1.0000 0.0000 ENUM('-1') NOT NULL
331+
test.t.cache_size 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL
332+
test.t.cycle_option 0 0 1 1 1 0 0.0000 0.0000 ENUM('0') NOT NULL
333+
test.t.cycle_count 0 0 1 1 1 0 0.0000 0.0000 ENUM('0') NOT NULL
334+
DROP SEQUENCE t;
335+
CREATE SEQUENCE t CACHE+1;
336+
SELECT * FROM t PROCEDURE ANALYSE();
337+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
338+
test.t.next_not_cached_value 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL
339+
test.t.minimum_value 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL
340+
test.t.maximum_value 9223372036854775806 9223372036854775806 19 19 0 0 9223372036854776000.0000 0.0000 ENUM('9223372036854775806') NOT NULL
341+
test.t.start_value 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL
342+
test.t.increment 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL
343+
test.t.cache_size 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL
344+
test.t.cycle_option 0 0 1 1 1 0 0.0000 0.0000 ENUM('0') NOT NULL
345+
test.t.cycle_count 0 0 1 1 1 0 0.0000 0.0000 ENUM('0') NOT NULL
346+
DROP SEQUENCE t;
347+
CREATE TABLE t (c INT) ENGINE=InnoDB;
348+
INSERT INTO t VALUES (0x31313131),(0x32323232);
349+
INSERT INTO t VALUES (0x31313131),(0x32323232);
350+
SELECT * FROM t LIMIT 1 PROCEDURE ANALYSE();
351+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
352+
test.t.c 825307441 842150450 9 9 0 0 833728945.5000 8421504.5000 ENUM('825307441','842150450') NOT NULL
353+
DROP TABLE t;
354+
CREATE TABLE t (f BIGINT) ENGINE=InnoDB;
355+
INSERT INTO t VALUES (1),(+1),(1),(1),(+1),(1),(1),(1),(1),(+1),(1),(1),(1),(20030000000000);
356+
SELECT * FROM t PROCEDURE ANALYSE();
357+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
358+
test.t.f 1 20030000000000 1 14 0 0 1430714285715.2144 5158513717681.4360 ENUM('1','20030000000000') NOT NULL
359+
DROP TABLE t;
360+
SET sql_mode=DEFAULT;
361+
# End of 10.11 tests

mysql-test/main/func_analyse.test

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Test of procedure analyse
33
#
44
-- source include/have_innodb.inc
5+
--source include/have_sequence.inc
56

67
--disable_warnings
78
drop table if exists t1,t2;
@@ -267,3 +268,85 @@ DROP TABLE t;
267268
--echo #
268269
--echo # End of 10.5 tests
269270
--echo #
271+
272+
--echo #
273+
--echo # MDEV-28374 UBSAN signed integer overflow PROCEDURE ANALYSE
274+
--echo #
275+
276+
SET sql_mode='';
277+
278+
CREATE TABLE t (a BIGINT);
279+
INSERT INTO t VALUES ('10000000000000'),('10000000000000');
280+
SELECT * FROM t PROCEDURE ANALYSE();
281+
282+
DROP TABLE t;
283+
284+
CREATE TABLE t (a BIGINT UNSIGNED);
285+
INSERT INTO t VALUES ('18446744073709551615'),('18446744073709551615');
286+
SELECT * FROM t PROCEDURE ANALYSE();
287+
288+
DROP TABLE t;
289+
290+
CREATE TABLE t (a BIGINT,KEY a USING BTREE (a));
291+
INSERT INTO t VALUES (0),('1'),('1'),('1'),('1'),('00010101'),('99991231'),('00101000000'),('691231000000'),('700101000000'),('991231235959'),('10000101000000'),('99991231235959'),('20030100000000'),('20030000000000');
292+
SELECT * FROM t PROCEDURE ANALYSE();
293+
294+
DROP TABLE t;
295+
296+
CREATE TABLE t (c BIGINT,c2 DATE,c3 BLOB,KEY(c)) ENGINE=InnoDB;
297+
INSERT INTO t VALUES (-1.e+308,1,1);
298+
SELECT * FROM t PROCEDURE ANALYSE();
299+
300+
DROP TABLE t;
301+
302+
CREATE TABLE t (c INT) ENGINE=InnoDB UNION=(t,t2) INSERT_METHOD=LAST;
303+
CREATE TABLE t3 LIKE t;
304+
INSERT INTO t VALUES (1),(2),(-685113344),(0);
305+
INSERT INTO t3 SELECT * FROM t;
306+
INSERT INTO t SELECT * FROM t;
307+
INSERT INTO t SELECT * FROM t;
308+
INSERT INTO t3 SELECT * FROM t;
309+
SELECT * FROM t3 PROCEDURE ANALYSE();
310+
311+
DROP TABLE t, t3;
312+
313+
CREATE TABLE t (c INT) ENGINE=InnoDB UNION=(t,t2) INSERT_METHOD=LAST;
314+
INSERT INTO t VALUES (1);
315+
INSERT INTO t VALUES (0xA9BD);
316+
INSERT INTO t (c) VALUES (ADDTIME(NOW(),1));
317+
CREATE TABLE c AS SELECT 1 A;
318+
SELECT * FROM t a,c,t b PROCEDURE ANALYSE();
319+
320+
DROP TABLE t, c;
321+
322+
CREATE TABLE t (c BIGINT);
323+
INSERT INTO t VALUES (1000000000000000);
324+
SELECT * FROM t PROCEDURE ANALYSE(0,0);
325+
326+
DROP TABLE t;
327+
328+
CREATE SEQUENCE t CACHE=1 MAXVALUE=0 INCREMENT=-1;
329+
SELECT * FROM t PROCEDURE ANALYSE();
330+
331+
DROP SEQUENCE t;
332+
333+
CREATE SEQUENCE t CACHE+1;
334+
SELECT * FROM t PROCEDURE ANALYSE();
335+
336+
DROP SEQUENCE t;
337+
338+
CREATE TABLE t (c INT) ENGINE=InnoDB;
339+
INSERT INTO t VALUES (0x31313131),(0x32323232);
340+
INSERT INTO t VALUES (0x31313131),(0x32323232);
341+
SELECT * FROM t LIMIT 1 PROCEDURE ANALYSE();
342+
343+
DROP TABLE t;
344+
345+
CREATE TABLE t (f BIGINT) ENGINE=InnoDB;
346+
INSERT INTO t VALUES (1),(+1),(1),(1),(+1),(1),(1),(1),(1),(+1),(1),(1),(1),(20030000000000);
347+
SELECT * FROM t PROCEDURE ANALYSE();
348+
349+
DROP TABLE t;
350+
SET sql_mode=DEFAULT;
351+
352+
--echo # End of 10.11 tests

mysql-test/suite/federated/federatedx.result

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2356,11 +2356,26 @@ pk
23562356
3
23572357
DROP TABLE t2_fed, t1, t2;
23582358
set @@optimizer_switch=@save_optimizer_switch;
2359-
DROP SERVER s;
23602359
# End of 10.5 tests
2360+
#
2361+
# MDEV-28374 UBSAN signed integer overflow PROCEDURE ANALYSE
2362+
#
2363+
CREATE TABLE t (a BIGINT);
2364+
INSERT INTO t VALUES ('-9223372036854775808');
2365+
INSERT INTO t SELECT * FROM t;
2366+
SELECT * FROM t PROCEDURE ANALYSE(2);
2367+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
2368+
test.t.a -9223372036854775808 -9223372036854775808 20 20 0 0 -9223372036854776000.0000 0.0000 BIGINT(20) NOT NULL
2369+
CREATE TABLE t_fed ENGINE=FEDERATED CONNECTION='s/t';
2370+
SELECT * FROM t_fed PROCEDURE ANALYSE(2);
2371+
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
2372+
test.t_fed.a -9223372036854775808 -9223372036854775808 20 20 0 0 -9223372036854776000.0000 0.0000 BIGINT(20) NOT NULL
2373+
DROP TABLE t, t_fed;
2374+
DROP SERVER s;
23612375
connection master;
23622376
DROP TABLE IF EXISTS federated.t1;
23632377
DROP DATABASE IF EXISTS federated;
23642378
connection slave;
23652379
DROP TABLE IF EXISTS federated.t1;
23662380
DROP DATABASE IF EXISTS federated;
2381+
# End of 10.11 tests

mysql-test/suite/federated/federatedx.test

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,8 +2086,23 @@ SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 );
20862086
DROP TABLE t2_fed, t1, t2;
20872087
set @@optimizer_switch=@save_optimizer_switch;
20882088

2089-
DROP SERVER s;
2090-
20912089
--echo # End of 10.5 tests
20922090

2091+
--echo #
2092+
--echo # MDEV-28374 UBSAN signed integer overflow PROCEDURE ANALYSE
2093+
--echo #
2094+
2095+
CREATE TABLE t (a BIGINT);
2096+
INSERT INTO t VALUES ('-9223372036854775808');
2097+
INSERT INTO t SELECT * FROM t;
2098+
SELECT * FROM t PROCEDURE ANALYSE(2);
2099+
2100+
CREATE TABLE t_fed ENGINE=FEDERATED CONNECTION='s/t';
2101+
SELECT * FROM t_fed PROCEDURE ANALYSE(2);
2102+
2103+
DROP TABLE t, t_fed;
2104+
2105+
DROP SERVER s;
20932106
source include/federated_cleanup.inc;
2107+
2108+
--echo # End of 10.11 tests

sql/sql_analyse.cc

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -555,25 +555,25 @@ void field_decimal::add()
555555
}
556556
}
557557

558-
559558
void field_longlong::add()
560559
{
561560
char buff[MAX_FIELD_WIDTH];
562-
longlong num = item->val_int();
563-
uint length = (uint) (longlong10_to_str(num, buff, -10) - buff);
561+
longlong numlong = item->val_int();
562+
double num = (double) numlong;
563+
uint length = (uint) (longlong10_to_str(numlong, buff, -10) - buff);
564564
TREE_ELEMENT *element;
565565

566566
if (item->null_value)
567567
{
568568
nulls++;
569569
return;
570570
}
571-
if (num == 0)
571+
if (num == 0.0)
572572
empty++;
573573

574574
if (room_in_tree)
575575
{
576-
if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
576+
if (!(element = tree_insert(&tree, (void*) &numlong, 0, tree.custom_arg)))
577577
{
578578
room_in_tree = 0; // Remove tree, out of RAM ?
579579
delete_tree(&tree, 0);
@@ -592,7 +592,8 @@ void field_longlong::add()
592592
if (!found)
593593
{
594594
found = 1;
595-
min_arg = max_arg = sum = num;
595+
min_arg = max_arg = numlong;
596+
sum = num;
596597
sum_sqr = num * num;
597598
min_length = max_length = length;
598599
}
@@ -604,19 +605,20 @@ void field_longlong::add()
604605
min_length = length;
605606
if (length > max_length)
606607
max_length = length;
607-
if (compare_longlong(&num, &min_arg) < 0)
608-
min_arg = num;
609-
if (compare_longlong(&num, &max_arg) > 0)
610-
max_arg = num;
608+
if (compare_longlong(&numlong, &min_arg) < 0)
609+
min_arg = numlong;
610+
if (compare_longlong(&numlong, &max_arg) > 0)
611+
max_arg = numlong;
611612
}
612613
} // field_longlong::add
613614

614615

615616
void field_ulonglong::add()
616617
{
617618
char buff[MAX_FIELD_WIDTH];
618-
longlong num = item->val_int();
619-
uint length = (uint) (longlong10_to_str(num, buff, 10) - buff);
619+
ulonglong numlong = item->val_int();
620+
double num= (double) numlong;
621+
uint length = (uint) (longlong10_to_str(numlong, buff, 10) - buff);
620622
TREE_ELEMENT *element;
621623

622624
if (item->null_value)
@@ -629,7 +631,7 @@ void field_ulonglong::add()
629631

630632
if (room_in_tree)
631633
{
632-
if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
634+
if (!(element = tree_insert(&tree, (void*) &numlong, 0, tree.custom_arg)))
633635
{
634636
room_in_tree = 0; // Remove tree, out of RAM ?
635637
delete_tree(&tree, 0);
@@ -648,7 +650,8 @@ void field_ulonglong::add()
648650
if (!found)
649651
{
650652
found = 1;
651-
min_arg = max_arg = sum = num;
653+
min_arg = max_arg = numlong;
654+
sum = num;
652655
sum_sqr = num * num;
653656
min_length = max_length = length;
654657
}
@@ -660,10 +663,10 @@ void field_ulonglong::add()
660663
min_length = length;
661664
if (length > max_length)
662665
max_length = length;
663-
if (compare_ulonglong((ulonglong*) &num, &min_arg) < 0)
664-
min_arg = num;
665-
if (compare_ulonglong((ulonglong*) &num, &max_arg) > 0)
666-
max_arg = num;
666+
if (compare_ulonglong(&numlong, &min_arg) < 0)
667+
min_arg = numlong;
668+
if (compare_ulonglong(&numlong, &max_arg) > 0)
669+
max_arg = numlong;
667670
}
668671
} // field_ulonglong::add
669672

0 commit comments

Comments
 (0)