|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #28547 Incorrect use of mysql_thread_init/end() functions
Submitted: 2004-05-27 20:06 UTC Modified: 2005-06-30 01:00 UTC
Avg. Score:3.3 ± 0.5
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: arkadi at mebius dot lv Assigned: georg (profile)
Status: No Feedback Package: MySQL related
PHP Version: 5CVS, 4CVS (2004-12-12) OS: *
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Bug Type:
From: arkadi at mebius dot lv
New email:
PHP Version: OS:


 [2004-05-27 20:06 UTC] arkadi at mebius dot lv
When PHP is compiled with --enable-experimental-zts (for Apache 2 Worker MPM) the following code is enabled in ext/mysql/php_mysql.c in ZEND_MODULE_STARTUP_D(mysql) and PHP_MSHUTDOWN_FUNCTION(mysql) functions:

#ifdef ZTS
# if MYSQL_VERSION_ID >= 40000
# endif

#ifdef ZTS
# if MYSQL_VERSION_ID >= 40000
# endif

The use of these function is incorrect and may lead to segmentation fault dependending on pthreads and mysql client library internal implementation details. In case of FreeBSD 4.x pthreads it is a reproducible process crash on module shutdown time.
mysql_thread_init() must be called at least once for every thread that use mysql, but only after mysql_init() is called somewhere in the program. mysql_thread_end() must be called only in case mysql_init() is called before or else it will call pthread_getspecific() with an unallocated pthread key as an argument with an undefined results (according to specification). Then (on FreeBSD and in my particular PHP build) it will try to deallocate condition variable using bogus memory address leading to segfault.

Program received signal SIGSEGV, Segmentation fault.
0x28483089 in _atomic_lock () from /usr/lib/
(gdb) bt
#0  0x28483089 in _atomic_lock () from /usr/lib/
#1  0x28482ffb in _spinlock_debug () from /usr/lib/
#2  0x2848a53a in pthread_cond_destroy () from /usr/lib/
#3  0x281f1f28 in my_thread_end () at my_thr_init.c:209
#4  0x281e6460 in mysql_thread_end () at libmysql.c:136
#5  0x807c2ee in zm_shutdown_mysql ()
#6  0x0 in ?? ()
(gdb) up 3
#3  0x281f1f28 in my_thread_end () at my_thr_init.c:209
209         pthread_cond_destroy(&tmp->suspend);
(gdb) p *tmp
$9 = {thr_errno = 136209024, suspend = 0x17, mutex = 0x81bb000, current_mutex = 0x0, current_cond = 0x81d6080, 
  pthread_self = 0x0, id = 0, cmp_length = 0, abort = 1130656883, init = 108 'l'}

On a related note I wish to say that PHP build process must link to (instead of in case thread safety is enabled. There is patch easily found by Google to ext/mysql/config.m4, for now I just edited Makefile.
Additional information:
- (near the end of the page)
- MySQL source: mysql-4.0.20/mysys/my_thr_init.c
mysql_thread_* function are just wrappers that calls my_thread_*.

my_bool my_thread_init(void)
  struct st_my_thread_var *tmp;
  my_bool error=0;

  fprintf(stderr,"my_thread_init(): thread_id=%ld\n",pthread_self());
#if !defined(__WIN__) || defined(USE_TLS) || ! defined(SAFE_MUTEX)

#if !defined(__WIN__) || defined(USE_TLS)
  if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
    fprintf(stderr,"my_thread_init() called more than once in thread %ld\n",
    goto end;
  if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
    error= 1;
    goto end;

    Skip initialization if the thread specific variable is already initialized
  if (
    goto end;
  tmp= &THR_KEY_mysys;
  tmp->id= ++thread_id;
#if defined(__WIN__) && defined(EMBEDDED_LIBRARY)
  tmp->thread_self= (pthread_t)getpid();
  pthread_cond_init(&tmp->suspend, NULL);
  tmp->init= 1;

#if !defined(__WIN__) || defined(USE_TLS) || ! defined(SAFE_MUTEX)
  return error;

void my_thread_end(void)
  struct st_my_thread_var *tmp;
  tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);

  fprintf(stderr,"my_thread_end(): tmp=%p,thread_id=%ld\n",
  if (tmp && tmp->init)
#if !defined(DBUG_OFF)
    /* tmp->dbug is allocated inside DBUG library */
    if (tmp->dbug)
#if !defined(__bsdi__) || defined(HAVE_mit_thread) /* bsdi dumps core here */
#if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS)
    tmp->init= 0;
  /* The following free has to be done, even if my_thread_var() is 0 */
#if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS)


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2005-06-22 21:53 UTC]
Please try using this CVS snapshot:
For Windows:

 [2005-06-30 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
PHP Copyright © 2001-2022 The PHP Group
All rights reserved.
Last updated: Thu Dec 01 04:05:54 2022 UTC