Commit 48126a57 authored by Magne Mahre's avatar Magne Mahre

Bug#11765237 - 58179: CANNOT START MYSQLD WITH APP VERIFIER

Bug#11763065 - 55730: KILL_SERVER() CALLS SETEVENT ON A NULL 
               HANDLE, SMEM_EVENT_CONNECT_REQUEST
      
Application Verifier is a Microsoft tool used for
detecting certain classes of programming errors.
In particular, MS Windows OS resource usage is
monitored for wrong usage (handles, thread local
storage, critical sections, ...)
      
In MySQL 5.5.x, an error was introduced where an
object on thread local storage was used before the
TLS and the object was created.
      
The fix has been to move the mysys initialization
to an earlier stage in the boot process when built for
Windows.  For non-win builds, the init already happens
early.

Some un-tangling of calls to my_init(), my_basic_init()
and my_thread_global_init() was done.  There is no
longer a need to do init in steps, so the full my_init()
is called instead of my_init_basic().
      
In addition,  Bug#11763065 was fixed.  The event handle
'smem_event_connect_request' is only created if
'opt_enable_shared_memory' is set.  When killing the
server, an event was flagged on the handle
unconditionally.  Added a test, so it will only be
flagged if created.
parent 626b835f
...@@ -806,8 +806,7 @@ extern pthread_mutexattr_t my_errorcheck_mutexattr; ...@@ -806,8 +806,7 @@ extern pthread_mutexattr_t my_errorcheck_mutexattr;
typedef ulong my_thread_id; typedef ulong my_thread_id;
extern my_bool my_thread_global_init(void); extern my_bool my_thread_global_init(void);
extern my_bool my_thread_basic_global_init(void); extern void my_thread_global_reinit(void);
extern void my_thread_basic_global_reinit(void);
extern void my_thread_global_end(void); extern void my_thread_global_end(void);
extern my_bool my_thread_init(void); extern my_bool my_thread_init(void);
extern void my_thread_end(void); extern void my_thread_end(void);
......
...@@ -641,7 +641,6 @@ extern int my_error_register(const char** (*get_errmsgs) (), ...@@ -641,7 +641,6 @@ extern int my_error_register(const char** (*get_errmsgs) (),
extern const char **my_error_unregister(int first, int last); extern const char **my_error_unregister(int first, int last);
extern void my_message(uint my_err, const char *str,myf MyFlags); extern void my_message(uint my_err, const char *str,myf MyFlags);
extern void my_message_stderr(uint my_err, const char *str, myf MyFlags); extern void my_message_stderr(uint my_err, const char *str, myf MyFlags);
extern my_bool my_basic_init(void);
extern my_bool my_init(void); extern my_bool my_init(void);
extern void my_end(int infoflag); extern void my_end(int infoflag);
extern int my_redel(const char *from, const char *to, int MyFlags); extern int my_redel(const char *from, const char *to, int MyFlags);
......
/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc /* Copyright (c) 2000, 2011 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -37,8 +37,6 @@ static my_bool win32_init_tcp_ip(); ...@@ -37,8 +37,6 @@ static my_bool win32_init_tcp_ip();
#define SCALE_USEC 10000 #define SCALE_USEC 10000
my_bool my_init_done= 0; my_bool my_init_done= 0;
/** True if @c my_basic_init() has been called. */
my_bool my_basic_init_done= 0;
uint mysys_usage_id= 0; /* Incremented for each my_init() */ uint mysys_usage_id= 0; /* Incremented for each my_init() */
ulong my_thread_stack_size= 65536; ulong my_thread_stack_size= 65536;
...@@ -56,23 +54,26 @@ static ulong atoi_octal(const char *str) ...@@ -56,23 +54,26 @@ static ulong atoi_octal(const char *str)
MYSQL_FILE *mysql_stdin= NULL; MYSQL_FILE *mysql_stdin= NULL;
static MYSQL_FILE instrumented_stdin; static MYSQL_FILE instrumented_stdin;
/**
Perform a limited initialisation of mysys. /*
This initialisation is sufficient to: Init my_sys functions and my_sys variabels
- allocate memory,
- read configuration files, SYNOPSIS
- parse command lines arguments. my_init()
To complete the mysys initialisation,
call my_init(). RETURN
@return 0 on success 0 ok
1 Couldn't initialize environment
*/ */
my_bool my_basic_init(void)
my_bool my_init(void)
{ {
char * str; char *str;
if (my_basic_init_done) if (my_init_done)
return 0; return 0;
my_basic_init_done= 1;
my_init_done= 1;
mysys_usage_id++; mysys_usage_id++;
my_umask= 0660; /* Default umask for new files */ my_umask= 0660; /* Default umask for new files */
...@@ -105,41 +106,11 @@ my_bool my_basic_init(void) ...@@ -105,41 +106,11 @@ my_bool my_basic_init(void)
#if defined(HAVE_PTHREAD_INIT) #if defined(HAVE_PTHREAD_INIT)
pthread_init(); /* Must be called before DBUG_ENTER */ pthread_init(); /* Must be called before DBUG_ENTER */
#endif #endif
if (my_thread_basic_global_init())
return 1;
/* $HOME is needed early to parse configuration files located in ~/ */ /* $HOME is needed early to parse configuration files located in ~/ */
if ((home_dir= getenv("HOME")) != 0) if ((home_dir= getenv("HOME")) != 0)
home_dir= intern_filename(home_dir_buff, home_dir); home_dir= intern_filename(home_dir_buff, home_dir);
return 0;
}
/*
Init my_sys functions and my_sys variabels
SYNOPSIS
my_init()
RETURN
0 ok
1 Couldn't initialize environment
*/
my_bool my_init(void)
{
if (my_init_done)
return 0;
my_init_done= 1;
if (my_basic_init())
return 1;
if (my_thread_global_init())
return 1;
{ {
DBUG_ENTER("my_init"); DBUG_ENTER("my_init");
DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown")); DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
...@@ -256,7 +227,6 @@ Voluntary context switches %ld, Involuntary context switches %ld\n", ...@@ -256,7 +227,6 @@ Voluntary context switches %ld, Involuntary context switches %ld\n",
#endif /* __WIN__ */ #endif /* __WIN__ */
my_init_done=0; my_init_done=0;
my_basic_init_done= 0;
} /* my_end */ } /* my_end */
......
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc /* Copyright (c) 2000, 2011 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -66,86 +66,40 @@ nptl_pthread_exit_hack_handler(void *arg __attribute((unused))) ...@@ -66,86 +66,40 @@ nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
static uint get_thread_lib(void); static uint get_thread_lib(void);
/** True if @c my_thread_basic_global_init() has been called. */ /** True if @c my_thread_global_init() has been called. */
static my_bool my_thread_basic_global_init_done= 0; static my_bool my_thread_global_init_done= 0;
/**
Perform a minimal initialisation of mysys, when compiled with threads.
The initialisation performed is sufficient to:
- allocate memory
- perform file operations
- use charsets
- use my_errno
@sa my_basic_init
@sa my_thread_basic_global_reinit
*/
my_bool my_thread_basic_global_init(void)
{
int pth_ret;
if (my_thread_basic_global_init_done)
return 0;
my_thread_basic_global_init_done= 1;
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
/*
Set mutex type to "fast" a.k.a "adaptive"
In this case the thread may steal the mutex from some other thread
that is waiting for the same mutex. This will save us some
context switches but may cause a thread to 'starve forever' while
waiting for the mutex (not likely if the code within the mutex is
short).
*/
pthread_mutexattr_init(&my_fast_mutexattr);
pthread_mutexattr_settype(&my_fast_mutexattr,
PTHREAD_MUTEX_ADAPTIVE_NP);
#endif
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
/*
Set mutex type to "errorcheck"
*/
pthread_mutexattr_init(&my_errorcheck_mutexattr);
pthread_mutexattr_settype(&my_errorcheck_mutexattr,
PTHREAD_MUTEX_ERRORCHECK);
#endif
mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
{
fprintf(stderr, "Can't initialize threads: error %d\n", pth_ret);
return 1;
}
if (my_thread_init())
return 1;
return 0;
}
/** /**
Re-initialize components initialized early with @c my_thread_basic_global_init. Re-initialize components initialized early with @c my_thread_global_init.
Some mutexes were initialized before the instrumentation. Some mutexes were initialized before the instrumentation.
Destroy + create them again, now that the instrumentation Destroy + create them again, now that the instrumentation
is in place. is in place.
This is safe, since this function() is called before creating new threads, This is safe, since this function() is called before creating new threads,
so the mutexes are not in use. so the mutexes are not in use.
*/ */
void my_thread_basic_global_reinit(void) void my_thread_global_reinit(void)
{ {
struct st_my_thread_var *tmp; struct st_my_thread_var *tmp;
DBUG_ASSERT(my_thread_basic_global_init_done); DBUG_ASSERT(my_thread_global_init_done);
#ifdef HAVE_PSI_INTERFACE #ifdef HAVE_PSI_INTERFACE
my_init_mysys_psi_keys(); my_init_mysys_psi_keys();
#endif #endif
mysql_mutex_destroy(&THR_LOCK_isam);
mysql_mutex_init(key_THR_LOCK_isam, &THR_LOCK_isam, MY_MUTEX_INIT_SLOW);
mysql_mutex_destroy(&THR_LOCK_heap);
mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST);
mysql_mutex_destroy(&THR_LOCK_net);
mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST);
mysql_mutex_destroy(&THR_LOCK_myisam);
mysql_mutex_init(key_THR_LOCK_myisam, &THR_LOCK_myisam, MY_MUTEX_INIT_SLOW);
mysql_mutex_destroy(&THR_LOCK_malloc); mysql_mutex_destroy(&THR_LOCK_malloc);
mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
...@@ -158,6 +112,9 @@ void my_thread_basic_global_reinit(void) ...@@ -158,6 +112,9 @@ void my_thread_basic_global_reinit(void)
mysql_mutex_destroy(&THR_LOCK_threads); mysql_mutex_destroy(&THR_LOCK_threads);
mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
mysql_cond_destroy(&THR_COND_threads);
mysql_cond_init(key_THR_COND_threads, &THR_COND_threads, NULL);
tmp= my_pthread_getspecific(struct st_my_thread_var*, THR_KEY_mysys); tmp= my_pthread_getspecific(struct st_my_thread_var*, THR_KEY_mysys);
DBUG_ASSERT(tmp); DBUG_ASSERT(tmp);
...@@ -181,7 +138,48 @@ void my_thread_basic_global_reinit(void) ...@@ -181,7 +138,48 @@ void my_thread_basic_global_reinit(void)
my_bool my_thread_global_init(void) my_bool my_thread_global_init(void)
{ {
if (my_thread_basic_global_init()) int pth_ret;
if (my_thread_global_init_done)
return 0;
my_thread_global_init_done= 1;
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
/*
Set mutex type to "fast" a.k.a "adaptive"
In this case the thread may steal the mutex from some other thread
that is waiting for the same mutex. This will save us some
context switches but may cause a thread to 'starve forever' while
waiting for the mutex (not likely if the code within the mutex is
short).
*/
pthread_mutexattr_init(&my_fast_mutexattr);
pthread_mutexattr_settype(&my_fast_mutexattr,
PTHREAD_MUTEX_ADAPTIVE_NP);
#endif
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
/*
Set mutex type to "errorcheck"
*/
pthread_mutexattr_init(&my_errorcheck_mutexattr);
pthread_mutexattr_settype(&my_errorcheck_mutexattr,
PTHREAD_MUTEX_ERRORCHECK);
#endif
if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
{
fprintf(stderr, "Can't initialize threads: error %d\n", pth_ret);
return 1;
}
mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
if (my_thread_init())
return 1; return 1;
thd_lib_detected= get_thread_lib(); thd_lib_detected= get_thread_lib();
...@@ -233,11 +231,11 @@ my_bool my_thread_global_init(void) ...@@ -233,11 +231,11 @@ my_bool my_thread_global_init(void)
install_sigabrt_handler(); install_sigabrt_handler();
#endif #endif
if (my_thread_init()) // if (my_thread_init())
{ // {
my_thread_global_end(); /* Clean up */ // my_thread_global_end(); /* Clean up */
return 1; // return 1;
} // }
return 0; return 0;
} }
...@@ -300,7 +298,7 @@ void my_thread_global_end(void) ...@@ -300,7 +298,7 @@ void my_thread_global_end(void)
mysql_mutex_destroy(&LOCK_gethostbyname_r); mysql_mutex_destroy(&LOCK_gethostbyname_r);
#endif #endif
my_thread_basic_global_init_done= 0; my_thread_global_init_done= 0;
} }
static my_thread_id thread_id= 0; static my_thread_id thread_id= 0;
......
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -1273,11 +1273,14 @@ static void __cdecl kill_server(int sig_ptr) ...@@ -1273,11 +1273,14 @@ static void __cdecl kill_server(int sig_ptr)
/* /*
Send event to smem_event_connect_request for aborting Send event to smem_event_connect_request for aborting
*/ */
if (!SetEvent(smem_event_connect_request)) if (opt_enable_shared_memory)
{ {
DBUG_PRINT("error", if (!SetEvent(smem_event_connect_request))
("Got error: %ld from SetEvent of smem_event_connect_request", {
GetLastError())); DBUG_PRINT("error",
("Got error: %ld from SetEvent of smem_event_connect_request",
GetLastError()));
}
} }
#endif #endif
...@@ -4216,11 +4219,14 @@ int mysqld_main(int argc, char **argv) ...@@ -4216,11 +4219,14 @@ int mysqld_main(int argc, char **argv)
to be able to read defaults files and parse options. to be able to read defaults files and parse options.
*/ */
my_progname= argv[0]; my_progname= argv[0];
if (my_basic_init()) #ifndef _WIN32
// For windows, my_init() is called from the win specific mysqld_main
if (my_init()) // init my_sys library & pthreads
{ {
fprintf(stderr, "my_basic_init() failed."); fprintf(stderr, "my_init() failed.");
return 1; return 1;
} }
#endif
orig_argc= argc; orig_argc= argc;
orig_argv= argv; orig_argv= argv;
...@@ -4319,11 +4325,10 @@ int mysqld_main(int argc, char **argv) ...@@ -4319,11 +4325,10 @@ int mysqld_main(int argc, char **argv)
recreate objects which were initialised early, recreate objects which were initialised early,
so that they are instrumented as well. so that they are instrumented as well.
*/ */
my_thread_basic_global_reinit(); my_thread_global_reinit();
} }
#endif /* HAVE_PSI_INTERFACE */ #endif /* HAVE_PSI_INTERFACE */
my_init(); // init my_sys library & pthreads
init_error_log_mutex(); init_error_log_mutex();
/* Set signal used to kill MySQL */ /* Set signal used to kill MySQL */
...@@ -4744,6 +4749,12 @@ int mysqld_main(int argc, char **argv) ...@@ -4744,6 +4749,12 @@ int mysqld_main(int argc, char **argv)
/* Must be initialized early for comparison of service name */ /* Must be initialized early for comparison of service name */
system_charset_info= &my_charset_utf8_general_ci; system_charset_info= &my_charset_utf8_general_ci;
if (my_init())
{
fprintf(stderr, "my_init() failed.");
return 1;
}
if (Service.GetOS()) /* true NT family */ if (Service.GetOS()) /* true NT family */
{ {
char file_path[FN_REFLEN]; char file_path[FN_REFLEN];
......
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