Commit a70c34bf authored by Georgi Kodinov's avatar Georgi Kodinov

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.
parent 7083cb0b
...@@ -1956,6 +1956,15 @@ dnl ...@@ -1956,6 +1956,15 @@ dnl
MYSQL_CHECK_TIME_T 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 ? # do we need #pragma interface/#pragma implementation ?
# yes if it's gcc 2.x, and not icc pretending to be gcc, and not cygwin # yes if it's gcc 2.x, and not icc pretending to be gcc, and not cygwin
......
...@@ -167,6 +167,11 @@ typedef uint rf_SetTimer; ...@@ -167,6 +167,11 @@ typedef uint rf_SetTimer;
#define SIZEOF_LONG 4 #define SIZEOF_LONG 4
#define SIZEOF_LONG_LONG 8 #define SIZEOF_LONG_LONG 8
#define SIZEOF_OFF_T 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 #ifdef _WIN64
#define SIZEOF_CHARP 8 #define SIZEOF_CHARP 8
#else #else
......
...@@ -53,6 +53,19 @@ typedef long my_time_t; ...@@ -53,6 +53,19 @@ typedef long my_time_t;
#define YY_PART_YEAR 70 #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 */ /* Flags to str_to_datetime */
#define TIME_FUZZY_DATE 1 #define TIME_FUZZY_DATE 1
#define TIME_DATETIME_ONLY 2 #define TIME_DATETIME_ONLY 2
......
...@@ -1323,4 +1323,21 @@ SELECT '2008-02-18' + INTERVAL 1 FRAC_SECOND; ...@@ -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 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; 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 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 End of 5.0 tests
...@@ -838,4 +838,23 @@ SELECT '2008-02-18' + INTERVAL 1 FRAC_SECOND; ...@@ -838,4 +838,23 @@ SELECT '2008-02-18' + INTERVAL 1 FRAC_SECOND;
--error ER_PARSE_ERROR --error ER_PARSE_ERROR
SELECT '2008-02-18' - INTERVAL 1 FRAC_SECOND; 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 --echo End of 5.0 tests
...@@ -776,7 +776,7 @@ SET @@myisam_mmap_size= 500M; ...@@ -776,7 +776,7 @@ SET @@myisam_mmap_size= 500M;
--echo # Bug #52315: utc_date() crashes when system time > year 2037 --echo # Bug #52315: utc_date() crashes when system time > year 2037
--echo # --echo #
--error 0, ER_UNKNOWN_ERROR --error 0, ER_WRONG_VALUE_FOR_VAR
SET TIMESTAMP=2*1024*1024*1024; SET TIMESTAMP=2*1024*1024*1024;
--echo #Should not crash --echo #Should not crash
--disable_result_log --disable_result_log
......
...@@ -985,7 +985,7 @@ my_system_gmt_sec(const MYSQL_TIME *t_src, long *my_timezone, ...@@ -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, with unsigned time_t tmp+= shift*86400L might result in a number,
larger then TIMESTAMP_MAX_VALUE, so another check will work. 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; tmp= 0;
return (my_time_t) tmp; return (my_time_t) tmp;
......
...@@ -2836,13 +2836,6 @@ static int init_common_variables(const char *conf_file_name, int argc, ...@@ -2836,13 +2836,6 @@ static int init_common_variables(const char *conf_file_name, int argc,
max_system_variables.pseudo_thread_id= (ulong)~0; max_system_variables.pseudo_thread_id= (ulong)~0;
server_start_time= flush_status_time= time((time_t*) 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()) if (init_thread_environment())
return 1; return 1;
mysql_init_variables(); mysql_init_variables();
...@@ -2882,6 +2875,13 @@ static int init_common_variables(const char *conf_file_name, int argc, ...@@ -2882,6 +2875,13 @@ static int init_common_variables(const char *conf_file_name, int argc,
mysql_slow_log.init_pthread_objects(); mysql_slow_log.init_pthread_objects();
mysql_bin_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) if (gethostname(glob_hostname,sizeof(glob_hostname)) < 0)
{ {
strmake(glob_hostname, STRING_WITH_LEN("localhost")); strmake(glob_hostname, STRING_WITH_LEN("localhost"));
......
...@@ -2714,14 +2714,14 @@ int set_var_collation_client::update(THD *thd) ...@@ -2714,14 +2714,14 @@ int set_var_collation_client::update(THD *thd)
bool sys_var_timestamp::check(THD *thd, set_var *var) bool sys_var_timestamp::check(THD *thd, set_var *var)
{ {
time_t val; longlong val;
var->save_result.ulonglong_value= var->value->val_int(); var->save_result.ulonglong_value= var->value->val_int();
val= (time_t) var->save_result.ulonglong_value; val= (longlong) var->save_result.ulonglong_value;
if (val < (time_t) MY_TIME_T_MIN || val > (time_t) MY_TIME_T_MAX) if (val != 0 && // this is how you set the default value
(val < TIMESTAMP_MIN_VALUE || val > TIMESTAMP_MAX_VALUE))
{ {
my_message(ER_UNKNOWN_ERROR, char buf[64];
"This version of MySQL doesn't support dates later than 2038", my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "timestamp", llstr(val, buf));
MYF(0));
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
......
...@@ -1710,7 +1710,7 @@ public: ...@@ -1710,7 +1710,7 @@ public:
/*TODO: this will be obsolete when we have support for 64 bit my_time_t */ /*TODO: this will be obsolete when we have support for 64 bit my_time_t */
inline bool is_valid_time() 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) inline void insert_id(ulonglong id_arg)
{ {
......
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