diff options
author | Georgi Kodinov <Georgi.Kodinov@Oracle.com> | 2011-02-02 18:51:35 +0200 |
---|---|---|
committer | Georgi Kodinov <Georgi.Kodinov@Oracle.com> | 2011-02-02 18:51:35 +0200 |
commit | 59f68983ffee45616a8ec255b5f13535236dd0ea (patch) | |
tree | 15a94e6095dd7f48a3a40e2c6d798d5f7b728b0e | |
parent | 4eb7054598196f474bfef50318a483c20bc29b87 (diff) | |
download | mariadb-git-59f68983ffee45616a8ec255b5f13535236dd0ea.tar.gz |
Fixes for Bug #55755 and Bug #52315 part 2
Bug #55755 : Date STD variable signness breaks server on FreeBSD and OpenBSD
* Added a check to configure on the size of time_t
* Created a macro to check for a valid time_t that is safe to use with datetime
functions and store in TIMESTAMP columns.
* Used the macro consistently instead of the ad-hoc checks introduced by 52315
* Fixed compliation warnings on platforms where the size of time_t is smaller than
the size of a long (e.g. OpenBSD 4.8 64 amd64).
Bug #52315: utc_date() crashes when system time > year 2037
* Added a correct check for the timestamp range instead of just variable size check to
SET TIMESTAMP.
* Added overflow checking before converting to time_t.
* Using a correct localized error message in this case instead of the generic error.
* Added a test suite.
* fixed the checks so that they check for unsigned time_t as well. Used the checks
consistently across the source code.
* fixed the original test case to expect the new error code.
-rw-r--r-- | configure.in | 9 | ||||
-rw-r--r-- | include/config-win.h | 5 | ||||
-rw-r--r-- | include/my_time.h | 13 | ||||
-rw-r--r-- | mysql-test/r/func_time.result | 17 | ||||
-rw-r--r-- | mysql-test/t/func_time.test | 19 | ||||
-rw-r--r-- | mysql-test/t/variables.test | 2 | ||||
-rw-r--r-- | sql-common/my_time.c | 2 | ||||
-rw-r--r-- | sql/mysqld.cc | 14 | ||||
-rw-r--r-- | sql/set_var.cc | 12 | ||||
-rw-r--r-- | sql/sql_class.h | 2 |
10 files changed, 79 insertions, 16 deletions
diff --git a/configure.in b/configure.in index fda56554879..523d36afaea 100644 --- a/configure.in +++ b/configure.in @@ -1956,6 +1956,15 @@ dnl MYSQL_CHECK_TIME_T +dnl +dnl check size of time_t +dnl + +AC_CHECK_SIZEOF(time_t, 8) +if test "$ac_cv_sizeof_time_t" -eq 0 +then + AC_MSG_ERROR("MySQL needs a time_t type.") +fi # do we need #pragma interface/#pragma implementation ? # yes if it's gcc 2.x, and not icc pretending to be gcc, and not cygwin diff --git a/include/config-win.h b/include/config-win.h index 84705809d7a..5e37d9e3a20 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -167,6 +167,11 @@ typedef uint rf_SetTimer; #define SIZEOF_LONG 4 #define SIZEOF_LONG_LONG 8 #define SIZEOF_OFF_T 8 +/* + The size of time_t depends on the compiler. + But it's 8 for all the supported VC versions. +*/ +#define SIZEOF_TIME_T 8 #ifdef _WIN64 #define SIZEOF_CHARP 8 #else diff --git a/include/my_time.h b/include/my_time.h index 014327d6fd8..5603535e0b7 100644 --- a/include/my_time.h +++ b/include/my_time.h @@ -53,6 +53,19 @@ typedef long my_time_t; #define YY_PART_YEAR 70 +/* + check for valid times only if the range of time_t is greater than + the range of my_time_t +*/ +#if SIZEOF_TIME_T > 4 || defined(TIME_T_UNSIGNED) +# define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \ + ((x) <= TIMESTAMP_MAX_VALUE && \ + (x) >= TIMESTAMP_MIN_VALUE) +#else +# define IS_TIME_T_VALID_FOR_TIMESTAMP(x) \ + ((x) >= TIMESTAMP_MIN_VALUE) +#endif + /* Flags to str_to_datetime */ #define TIME_FUZZY_DATE 1 #define TIME_DATETIME_ONLY 2 diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index b3505795494..8638fb09e5a 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1323,4 +1323,21 @@ SELECT '2008-02-18' + INTERVAL 1 FRAC_SECOND; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FRAC_SECOND' at line 1 SELECT '2008-02-18' - INTERVAL 1 FRAC_SECOND; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FRAC_SECOND' at line 1 +# +# Bug #52315 part 2 : utc_date() crashes when system time > year 2037 +# +SET TIMESTAMP=-147490000; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483648; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483646; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483647; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=0; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=-1; +SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=1; +SELECT UTC_TIMESTAMP(); End of 5.0 tests diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 65d8764f2ce..475938b4458 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -838,4 +838,23 @@ SELECT '2008-02-18' + INTERVAL 1 FRAC_SECOND; --error ER_PARSE_ERROR SELECT '2008-02-18' - INTERVAL 1 FRAC_SECOND; + +--echo # +--echo # Bug #52315 part 2 : utc_date() crashes when system time > year 2037 +--echo # + +--disable_result_log +--error ER_WRONG_VALUE_FOR_VAR +SET TIMESTAMP=-147490000; SELECT UTC_TIMESTAMP(); +--error ER_WRONG_VALUE_FOR_VAR +SET TIMESTAMP=2147483648; SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483646; SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=2147483647; SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=0; SELECT UTC_TIMESTAMP(); +--error ER_WRONG_VALUE_FOR_VAR +SET TIMESTAMP=-1; SELECT UTC_TIMESTAMP(); +SET TIMESTAMP=1; SELECT UTC_TIMESTAMP(); +--enable_result_log + + --echo End of 5.0 tests diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 73e5bbd9d87..778fb133045 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -776,7 +776,7 @@ SET @@myisam_mmap_size= 500M; --echo # Bug #52315: utc_date() crashes when system time > year 2037 --echo # ---error 0, ER_UNKNOWN_ERROR +--error 0, ER_WRONG_VALUE_FOR_VAR SET TIMESTAMP=2*1024*1024*1024; --echo #Should not crash --disable_result_log diff --git a/sql-common/my_time.c b/sql-common/my_time.c index ed1279f7afb..07cb8b25c46 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -985,7 +985,7 @@ my_system_gmt_sec(const MYSQL_TIME *t_src, long *my_timezone, with unsigned time_t tmp+= shift*86400L might result in a number, larger then TIMESTAMP_MAX_VALUE, so another check will work. */ - if ((tmp < TIMESTAMP_MIN_VALUE) || (tmp > TIMESTAMP_MAX_VALUE)) + if (!IS_TIME_T_VALID_FOR_TIMESTAMP(tmp)) tmp= 0; return (my_time_t) tmp; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5f84d15588d..f026bab1c32 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2836,13 +2836,6 @@ static int init_common_variables(const char *conf_file_name, int argc, max_system_variables.pseudo_thread_id= (ulong)~0; server_start_time= flush_status_time= time((time_t*) 0); - /* TODO: remove this when my_time_t is 64 bit compatible */ - if (server_start_time >= (time_t) MY_TIME_T_MAX) - { - sql_print_error("This MySQL server doesn't support dates later then 2038"); - return 1; - } - if (init_thread_environment()) return 1; mysql_init_variables(); @@ -2882,6 +2875,13 @@ static int init_common_variables(const char *conf_file_name, int argc, mysql_slow_log.init_pthread_objects(); mysql_bin_log.init_pthread_objects(); + /* TODO: remove this when my_time_t is 64 bit compatible */ + if (!IS_TIME_T_VALID_FOR_TIMESTAMP(server_start_time)) + { + sql_print_error("This MySQL server doesn't support dates later then 2038"); + return 1; + } + if (gethostname(glob_hostname,sizeof(glob_hostname)) < 0) { strmake(glob_hostname, STRING_WITH_LEN("localhost")); diff --git a/sql/set_var.cc b/sql/set_var.cc index 9c327504577..fbc7cdbc232 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2714,14 +2714,14 @@ int set_var_collation_client::update(THD *thd) bool sys_var_timestamp::check(THD *thd, set_var *var) { - time_t val; + longlong val; var->save_result.ulonglong_value= var->value->val_int(); - val= (time_t) var->save_result.ulonglong_value; - if (val < (time_t) MY_TIME_T_MIN || val > (time_t) MY_TIME_T_MAX) + val= (longlong) var->save_result.ulonglong_value; + if (val != 0 && // this is how you set the default value + (val < TIMESTAMP_MIN_VALUE || val > TIMESTAMP_MAX_VALUE)) { - my_message(ER_UNKNOWN_ERROR, - "This version of MySQL doesn't support dates later than 2038", - MYF(0)); + char buf[64]; + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "timestamp", llstr(val, buf)); return TRUE; } return FALSE; diff --git a/sql/sql_class.h b/sql/sql_class.h index 2f4af15c02d..70086e2d944 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1710,7 +1710,7 @@ public: /*TODO: this will be obsolete when we have support for 64 bit my_time_t */ inline bool is_valid_time() { - return (start_time < (time_t) MY_TIME_T_MAX); + return (IS_TIME_T_VALID_FOR_TIMESTAMP(start_time)); } inline void insert_id(ulonglong id_arg) { |