]> granicus.if.org Git - php/commitdiff
Fix bug #66283 (Segmentation fault after memory_limit)
authorJohannes Schlüter <johannes@php.net>
Tue, 21 Jan 2014 15:28:30 +0000 (16:28 +0100)
committerJohannes Schlüter <johannes@php.net>
Tue, 21 Jan 2014 15:28:30 +0000 (16:28 +0100)
There are situations where mysqlnd dupliates zvals while freeing result
sets. If the memory_limit is reached during this operation the engine
will bailout. This patch makes sure that a later attempt (during
RSHIUTDOWN) won't cause a double free, instead we rely on the engine to
free emalloc()ed memory after bailout.

NEWS
ext/mysqlnd/mysqlnd_result.c

diff --git a/NEWS b/NEWS
index f542bcfd492e5231d2b9a83ada152966068f0c08..7715e2a68f4aad4e3f7ee5684c2548ad00040bb0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,9 @@ PHP                                                                        NEWS
   . Fixed bug #66286 (Incorrect object comparison with inheritance). (Nikita)
   . Fixed bug #66509 (copy() arginfo has changed starting from 5.4). (willfitch)
 
+- mysqlnd
+  . Fixed bug #66283 (Segmentation fault after memory_limit). (Johannes)
+
 - PDO_pgsql:
   . Fixed bug #62479 (PDO-psql cannot connect if password contains spaces) (willfitch, iliaa)
 
index cb15657601a9f62354db0bd973a788301a67f760..08149264839c46ca35771e0f434bc6029744cd32 100644 (file)
@@ -198,9 +198,11 @@ MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC)
        if (set->data) {
                unsigned int copy_on_write_performed = 0;
                unsigned int copy_on_write_saved = 0;
+               zval **data = set->data;
+               set->data = NULL; /* prevent double free if following loop is interrupted */
 
                for (row = set->row_count - 1; row >= 0; row--) {
-                       zval **current_row = set->data + row * field_count;
+                       zval **current_row = data + row * field_count;
                        MYSQLND_MEMORY_POOL_CHUNK *current_buffer = set->row_buffers[row];
                        int64_t col;
 
@@ -222,8 +224,7 @@ MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC)
 
                MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_COPY_ON_WRITE_PERFORMED, copy_on_write_performed,
                                                                                          STAT_COPY_ON_WRITE_SAVED, copy_on_write_saved);
-               mnd_efree(set->data);
-               set->data = NULL;
+               mnd_efree(data);
        }
 
        if (set->row_buffers) {