]> granicus.if.org Git - php/commitdiff
Fix double-free, introduced lately
authorAndrey Hristov <andrey@php.net>
Tue, 24 Jun 2008 13:19:29 +0000 (13:19 +0000)
committerAndrey Hristov <andrey@php.net>
Tue, 24 Jun 2008 13:19:29 +0000 (13:19 +0000)
ext/mysql/php_mysql.c
ext/mysqli/mysqli.c
ext/mysqlnd/mysqlnd.c
ext/mysqlnd/mysqlnd_palloc.c

index 0e5319cb2186b2733701dd137887b6ea5747b5a7..594a1de6231b3712bbb6c529cdcbbf05f60c2646 100644 (file)
@@ -365,6 +365,9 @@ static void _close_mysql_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC)
        void (*handler) (int);
 
        handler = signal(SIGPIPE, SIG_IGN);
+#ifdef MYSQL_USE_MYSQLND
+       mysqlnd_end_psession(link->conn);
+#endif
        mysql_close(link->conn);
        signal(SIGPIPE, handler);
 
@@ -775,11 +778,12 @@ static void php_mysql_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
                        /* ensure that the link did not die */
                        if (mysql_ping(mysql->conn)) {
                                if (mysql_errno(mysql->conn) == 2006) {
-#ifndef MYSQL_USE_MYSQLND
-                                       if (mysql_real_connect(mysql->conn, host, user, passwd, NULL, port, socket, client_flags)==NULL)
-#else
+#ifdef MYSQL_USE_MYSQLND
+                                       mysqlnd_end_psession(mysql->conn);
                                        if (mysqlnd_connect(mysql->conn, host, user, passwd, 0, NULL, 0, 
                                                                                port, socket, client_flags, MySG(mysqlnd_thd_zval_cache) TSRMLS_CC) == NULL)
+#else
+                                       if (mysql_real_connect(mysql->conn, host, user, passwd, NULL, port, socket, client_flags)==NULL)
 #endif
                                        {
                                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Link to server lost, unable to reconnect");
index 2fc0b00cd0f4d20c4a69567b9678590243db38b7..f8350be3fbbe76ac438b6c4bc4d1bb7eacabf5be 100644 (file)
@@ -232,6 +232,9 @@ static void mysqli_link_free_storage(void *object TSRMLS_DC)
                MY_MYSQL *mysql = (MY_MYSQL *)my_res->ptr;
                if (mysql->mysql) {
                        if (!mysql->persistent) {
+#ifdef MYSQLI_USE_MYSQLND
+                               mysqlnd_end_psession(mysql->mysql);
+#endif
                                mysqli_close(mysql->mysql, MYSQLI_CLOSE_IMPLICIT);
                        } else {
                                zend_rsrc_list_entry *le;
index cd21ebed56d078483a66f2c4b65089fd27cd93b1..5f50d80e0649aaf15bf2a916a8f263b62e1e859c 100644 (file)
@@ -451,7 +451,11 @@ PHPAPI void _mysqlnd_restart_psession(MYSQLND *conn, MYSQLND_THD_ZVAL_PCACHE *ca
                mnd_pefree(conn->last_message, conn->persistent);
                conn->last_message = NULL;
        }
-       conn->zval_cache = cache;
+       /*
+         The thd zval cache is always freed on request shutdown, so this has happened already.
+         Don't touch the old value! Get new reference
+       */
+       conn->zval_cache = mysqlnd_palloc_get_thd_cache_reference(cache);
        DBG_VOID_RETURN;
 }
 /* }}} */
@@ -461,16 +465,8 @@ PHPAPI void _mysqlnd_restart_psession(MYSQLND *conn, MYSQLND_THD_ZVAL_PCACHE *ca
 PHPAPI void _mysqlnd_end_psession(MYSQLND *conn TSRMLS_DC)
 {
        DBG_ENTER("_mysqlnd_end_psession");
-       /*
-         BEWARE!!!! This will have a problem with a query cache.
-         We need to move the data out of the zval cache before we end the psession.
-         Or we will use nirvana pointers!!
-       */
-       if (conn->zval_cache) {
-               DBG_INF("Freeing zval cache reference");
-               mysqlnd_palloc_free_thd_cache_reference(&conn->zval_cache);
-               conn->zval_cache = NULL;
-       }
+       /* The thd zval cache is always freed on request shutdown, so this has happened already */
+       conn->zval_cache = NULL;
        DBG_VOID_RETURN;
 }
 /* }}} */
index cff217eaaeb949bcfbd07fd9268a85e771b2fe9e..f429af49f5c418d474dbafae6fbd14cab62bd924 100644 (file)
@@ -518,6 +518,15 @@ PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * thd_cache TSRMLS
                return;
        }
 
+       /*
+         !!! 080624 !!!
+         If the user has used Persistent Connections the reference counter
+         of the cache is not 1 but > 1 . Because the Pconns don't are not signalised
+         during RSHUT, then we need to take care here to decrease the counter.
+         A more proper fix will be to array_walk our pconns in RSHUT and ask them to
+         free their thd reference. This should be implemented sooner or later!
+       */
+       
        /*
          Keep in mind that for pthreads pthread_equal() should be used to be
          fully standard compliant. However, the PHP code all-around, incl. the
@@ -532,6 +541,8 @@ PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * thd_cache TSRMLS
        p = thd_cache->gc_list.ptr_line;
 
        LOCK_PCACHE(cache);
+       /* We need to decrease Main cache's references as pconns don't clean correctly */
+       cache->references -= (thd_cache->references - 1); /* we start with 1 initial reference */
        while (p < thd_cache->gc_list.last_added) {
                (*p)->point_type = MYSQLND_POINTS_FREE;
                *(--cache->free_list.last_added) = *p;
@@ -543,6 +554,8 @@ PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * thd_cache TSRMLS
        }
        UNLOCK_PCACHE(cache);
 
+       /* We need to decrease thd cache's references as pconns don't clean correctly. See above! */
+       thd_cache->references = 1;
        mysqlnd_palloc_free_thd_cache_reference(&thd_cache);
 
        DBG_VOID_RETURN;