From bc9b4834e1f95f02008e41b8e5ce62968befd53a Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Thu, 4 Oct 2007 10:20:00 +0500 Subject: [PATCH 1/3] Fix for bug #31069: crash in 'sounds like' and for bug #31070: crash during conversion of charsets Problem: passing a 0 byte length string to some my_mb_wc_XXX() functions leads to server crash due to improper argument check. Fix: properly check arguments passed to my_mb_wc_XXX() functions. --- mysql-test/include/ctype_common.inc | 9 +++++++++ mysql-test/r/ctype_big5.result | 11 +++++++++++ mysql-test/r/ctype_euckr.result | 11 +++++++++++ mysql-test/r/ctype_gb2312.result | 11 +++++++++++ mysql-test/r/ctype_gbk.result | 11 +++++++++++ mysql-test/r/ctype_uca.result | 11 +++++++++++ strings/ctype-big5.c | 4 ++-- strings/ctype-cp932.c | 4 ++-- strings/ctype-euc_kr.c | 4 ++-- strings/ctype-gb2312.c | 4 +--- strings/ctype-sjis.c | 4 ++-- 11 files changed, 73 insertions(+), 11 deletions(-) diff --git a/mysql-test/include/ctype_common.inc b/mysql-test/include/ctype_common.inc index 202c508a9c9..9ee0a40c8ce 100644 --- a/mysql-test/include/ctype_common.inc +++ b/mysql-test/include/ctype_common.inc @@ -51,6 +51,15 @@ SELECT c1 as want1result from t1 where c1 like 'locatio%'; SELECT c1 as want1result from t1 where c1 like 'location%'; DROP TABLE t1; +# +# Bug #31070: crash during conversion of charsets +# +create table t1 (a set('a') not null); +insert into t1 values (),(); +select cast(a as char(1)) from t1; +select a sounds like a from t1; +drop table t1; + DROP DATABASE d1; # Restore settings USE test; diff --git a/mysql-test/r/ctype_big5.result b/mysql-test/r/ctype_big5.result index 6574908101c..a2651db6308 100644 --- a/mysql-test/r/ctype_big5.result +++ b/mysql-test/r/ctype_big5.result @@ -52,6 +52,17 @@ SELECT c1 as want1result from t1 where c1 like 'location%'; want1result location DROP TABLE t1; +create table t1 (a set('a') not null); +insert into t1 values (),(); +select cast(a as char(1)) from t1; +cast(a as char(1)) + + +select a sounds like a from t1; +a sounds like a +1 +1 +drop table t1; DROP DATABASE d1; USE test; SET character_set_server= @safe_character_set_server; diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result index 6017bc07763..2d9f8d217e6 100644 --- a/mysql-test/r/ctype_euckr.result +++ b/mysql-test/r/ctype_euckr.result @@ -52,6 +52,17 @@ SELECT c1 as want1result from t1 where c1 like 'location%'; want1result location DROP TABLE t1; +create table t1 (a set('a') not null); +insert into t1 values (),(); +select cast(a as char(1)) from t1; +cast(a as char(1)) + + +select a sounds like a from t1; +a sounds like a +1 +1 +drop table t1; DROP DATABASE d1; USE test; SET character_set_server= @safe_character_set_server; diff --git a/mysql-test/r/ctype_gb2312.result b/mysql-test/r/ctype_gb2312.result index 314c336bab9..04c318e83a8 100644 --- a/mysql-test/r/ctype_gb2312.result +++ b/mysql-test/r/ctype_gb2312.result @@ -52,6 +52,17 @@ SELECT c1 as want1result from t1 where c1 like 'location%'; want1result location DROP TABLE t1; +create table t1 (a set('a') not null); +insert into t1 values (),(); +select cast(a as char(1)) from t1; +cast(a as char(1)) + + +select a sounds like a from t1; +a sounds like a +1 +1 +drop table t1; DROP DATABASE d1; USE test; SET character_set_server= @safe_character_set_server; diff --git a/mysql-test/r/ctype_gbk.result b/mysql-test/r/ctype_gbk.result index 241539ecf42..064c0bc2acf 100644 --- a/mysql-test/r/ctype_gbk.result +++ b/mysql-test/r/ctype_gbk.result @@ -52,6 +52,17 @@ SELECT c1 as want1result from t1 where c1 like 'location%'; want1result location DROP TABLE t1; +create table t1 (a set('a') not null); +insert into t1 values (),(); +select cast(a as char(1)) from t1; +cast(a as char(1)) + + +select a sounds like a from t1; +a sounds like a +1 +1 +drop table t1; DROP DATABASE d1; USE test; SET character_set_server= @safe_character_set_server; diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 91ee427efb4..3d8bd33fb19 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -2371,6 +2371,17 @@ SELECT c1 as want1result from t1 where c1 like 'location%'; want1result location DROP TABLE t1; +create table t1 (a set('a') not null); +insert into t1 values (),(); +select cast(a as char(1)) from t1; +cast(a as char(1)) + + +select a sounds like a from t1; +a sounds like a +1 +1 +drop table t1; DROP DATABASE d1; USE test; SET character_set_server= @safe_character_set_server; diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index 89a40b15288..90917229769 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -6256,12 +6256,12 @@ my_mb_wc_big5(CHARSET_INFO *cs __attribute__((unused)), my_wc_t *pwc,const uchar *s,const uchar *e) { - int hi=s[0]; + int hi; if (s >= e) return MY_CS_TOOSMALL; - if (hi<0x80) + if ((hi= s[0]) < 0x80) { pwc[0]=hi; return 1; diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c index e8c62b0315e..3752b2e4118 100644 --- a/strings/ctype-cp932.c +++ b/strings/ctype-cp932.c @@ -5352,12 +5352,12 @@ my_wc_mb_cp932(CHARSET_INFO *cs __attribute__((unused)), static int my_mb_wc_cp932(CHARSET_INFO *cs __attribute__((unused)), my_wc_t *pwc, const uchar *s, const uchar *e){ - int hi=s[0]; + int hi; if (s >= e) return MY_CS_TOOSMALL; - if (hi < 0x80) + if ((hi= s[0]) < 0x80) { pwc[0]=hi; return 1; diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index 25ac416ac60..50300f3c140 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -8614,12 +8614,12 @@ my_mb_wc_euc_kr(CHARSET_INFO *cs __attribute__((unused)), my_wc_t *pwc, const uchar *s, const uchar *e) { - int hi=s[0]; + int hi; if (s >= e) return MY_CS_TOOSMALL; - if (hi<0x80) + if ((hi= s[0]) < 0x80) { pwc[0]=hi; return 1; diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index 556f485945b..e81f9d3cf0c 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -5665,12 +5665,10 @@ my_mb_wc_gb2312(CHARSET_INFO *cs __attribute__((unused)), my_wc_t *pwc, const uchar *s, const uchar *e){ int hi; - hi=(int) s[0]; - if (s >= e) return MY_CS_TOOSMALL; - if (hi<0x80) + if ((hi= s[0]) < 0x80) { pwc[0]=hi; return 1; diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 38a9c9a6428..92d6b4dc2ae 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -4512,12 +4512,12 @@ mb: static int my_mb_wc_sjis(CHARSET_INFO *cs __attribute__((unused)), my_wc_t *pwc, const uchar *s, const uchar *e){ - int hi=s[0]; + int hi; if (s >= e) return MY_CS_TOOSMALL; - if (hi < 0x80) + if ((hi= s[0]) < 0x80) { pwc[0]=hi; return 1; From 6e6727d24480effb2fe401bab970ad12f80ca7fe Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Thu, 4 Oct 2007 12:09:22 +0500 Subject: [PATCH 2/3] merging: results adjusted --- mysql-test/r/ctype_big5.result | 2 ++ mysql-test/r/ctype_euckr.result | 2 ++ mysql-test/r/ctype_gb2312.result | 2 ++ mysql-test/r/ctype_gbk.result | 2 ++ mysql-test/r/ctype_uca.result | 2 ++ 5 files changed, 10 insertions(+) diff --git a/mysql-test/r/ctype_big5.result b/mysql-test/r/ctype_big5.result index 485b6ec00ae..b190273cc64 100644 --- a/mysql-test/r/ctype_big5.result +++ b/mysql-test/r/ctype_big5.result @@ -54,6 +54,8 @@ location DROP TABLE t1; create table t1 (a set('a') not null); insert into t1 values (),(); +Warnings: +Warning 1364 Field 'a' doesn't have a default value select cast(a as char(1)) from t1; cast(a as char(1)) diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result index 2d9f8d217e6..b9619370d4c 100644 --- a/mysql-test/r/ctype_euckr.result +++ b/mysql-test/r/ctype_euckr.result @@ -54,6 +54,8 @@ location DROP TABLE t1; create table t1 (a set('a') not null); insert into t1 values (),(); +Warnings: +Warning 1364 Field 'a' doesn't have a default value select cast(a as char(1)) from t1; cast(a as char(1)) diff --git a/mysql-test/r/ctype_gb2312.result b/mysql-test/r/ctype_gb2312.result index 04c318e83a8..90c94c3b299 100644 --- a/mysql-test/r/ctype_gb2312.result +++ b/mysql-test/r/ctype_gb2312.result @@ -54,6 +54,8 @@ location DROP TABLE t1; create table t1 (a set('a') not null); insert into t1 values (),(); +Warnings: +Warning 1364 Field 'a' doesn't have a default value select cast(a as char(1)) from t1; cast(a as char(1)) diff --git a/mysql-test/r/ctype_gbk.result b/mysql-test/r/ctype_gbk.result index bc717736e3e..fe90c7bff29 100644 --- a/mysql-test/r/ctype_gbk.result +++ b/mysql-test/r/ctype_gbk.result @@ -54,6 +54,8 @@ location DROP TABLE t1; create table t1 (a set('a') not null); insert into t1 values (),(); +Warnings: +Warning 1364 Field 'a' doesn't have a default value select cast(a as char(1)) from t1; cast(a as char(1)) diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 8a4f0fd3698..e676d5a5ca0 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -2589,6 +2589,8 @@ location DROP TABLE t1; create table t1 (a set('a') not null); insert into t1 values (),(); +Warnings: +Warning 1364 Field 'a' doesn't have a default value select cast(a as char(1)) from t1; cast(a as char(1)) From 1ba3f4f56b57bcf6266beae20da6a06eda436964 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Thu, 4 Oct 2007 12:34:00 +0400 Subject: [PATCH 3/3] Issue a warning if a user sets an option or a variable to a value that is greater than a defined maximum for the option/variable. This is for bug #29446 "Specifying a myisam_sort_buffer > 4GB on 64 bit machines not possible". Support for myisam_sort_buffer_size > 4 GB on 64-bit Windows will be looked at later in 5.2. --- mysql-test/r/variables.result | 2 ++ mysql-test/t/variables.test | 1 + mysys/my_getopt.c | 16 ++++++++++++++++ sql/set_var.cc | 15 +++++++++++++++ 4 files changed, 34 insertions(+) diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 3d76f8e4a90..9e52fbeac1a 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -218,6 +218,8 @@ show variables like 'net_buffer_length'; Variable_name Value net_buffer_length 1024 set net_buffer_length=2000000000; +Warnings: +Warning 1292 Truncated incorrect net_buffer_length value: '2000000000' show variables like 'net_buffer_length'; Variable_name Value net_buffer_length 1048576 diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 0ad85a32568..ccd487a72ea 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -139,6 +139,7 @@ show global variables like 'net_%'; show session variables like 'net_%'; set net_buffer_length=1; show variables like 'net_buffer_length'; +--warning 1292 set net_buffer_length=2000000000; show variables like 'net_buffer_length'; diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 623c48b2e55..71630e1b4c2 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -19,6 +19,7 @@ #include #include #include +#include static void default_reporter(enum loglevel level, const char *format, ...); my_error_reporter my_getopt_error_reporter= &default_reporter; @@ -693,7 +694,15 @@ static longlong eval_num_suffix (char *argument, int *error, char *option_name) longlong num; *error= 0; + errno= 0; num= strtoll(argument, &endchar, 10); + if (errno == ERANGE) + { + my_getopt_error_reporter(ERROR_LEVEL, + "Incorrect integer value: '%s'", argument); + *error= 1; + return 0; + } if (*endchar == 'k' || *endchar == 'K') num*= 1024L; else if (*endchar == 'm' || *endchar == 'M') @@ -730,7 +739,14 @@ static longlong getopt_ll(char *arg, const struct my_option *optp, int *err) num= eval_num_suffix(arg, err, (char*) optp->name); if (num > 0 && (ulonglong) num > (ulonglong) optp->max_value && optp->max_value) /* if max value is not set -> no upper limit */ + { + char buf[22]; + my_getopt_error_reporter(WARNING_LEVEL, + "Truncated incorrect %s value: '%s'", + optp->name, llstr(num, buf)); + num= (ulonglong) optp->max_value; + } num= ((num - optp->sub_size) / block_size); num= (longlong) (num * block_size); return max(num, optp->min_value); diff --git a/sql/set_var.cc b/sql/set_var.cc index e1246617d84..5c76019efc6 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1532,16 +1532,31 @@ bool sys_var_thd_ulong::check(THD *thd, set_var *var) bool sys_var_thd_ulong::update(THD *thd, set_var *var) { ulonglong tmp= var->save_result.ulonglong_value; + char buf[22]; + bool truncated= false; /* Don't use bigger value than given with --maximum-variable-name=.. */ if ((ulong) tmp > max_system_variables.*offset) + { + truncated= true; + llstr(tmp, buf); tmp= max_system_variables.*offset; + } #if SIZEOF_LONG == 4 /* Avoid overflows on 32 bit systems */ if (tmp > (ulonglong) ~(ulong) 0) + { + truncated= true; + llstr(tmp, buf); tmp= ((ulonglong) ~(ulong) 0); + } #endif + if (truncated) + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), name, + buf); if (option_limits) tmp= (ulong) getopt_ull_limit_value(tmp, option_limits);