From: Nikita Popov Date: Thu, 12 Sep 2019 11:17:27 +0000 (+0200) Subject: Fix bug #78525 X-Git-Tag: php-7.4.0RC2~34^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=df982da5874856e3a4d6bbbefb8d3be97261a6cf;p=php Fix bug #78525 When calling free_result_buffers(), also free field metadata and restore the mempool state to what it was before any allocations have been made. Remove the mempool save/restore logic for the inner result set as this is now handled on a higher level. --- diff --git a/NEWS b/NEWS index 0e2a2c6482..5eda302329 100644 --- a/NEWS +++ b/NEWS @@ -3,9 +3,13 @@ PHP NEWS ?? ??? ????, PHP 7.3.11 - Exif : - .Fixed bug #78442 ('Illegal component' on exif_read_data since PHP7) + . Fixed bug #78442 ('Illegal component' on exif_read_data since PHP7) (Kalle) +- Mysqlnd: + . Fixed bug #78525 (Memory leak in pdo when reusing native prepared + statements). (Nikita) + 12 Sep 2019, PHP 7.3.10RC1 - Core: diff --git a/ext/mysqlnd/mysqlnd_block_alloc.c b/ext/mysqlnd/mysqlnd_block_alloc.c index 10f6bd3b6d..cba7530c8d 100644 --- a/ext/mysqlnd/mysqlnd_block_alloc.c +++ b/ext/mysqlnd/mysqlnd_block_alloc.c @@ -200,6 +200,9 @@ PHPAPI void mysqlnd_mempool_restore_state(MYSQLND_MEMORY_POOL * pool) { DBG_ENTER("mysqlnd_mempool_restore_state"); +#if ZEND_DEBUG + ZEND_ASSERT(pool->checkpoint); +#endif if (pool->checkpoint) { mysqlnd_arena_release(&pool->arena, pool->checkpoint); pool->last = NULL; diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index 06a7793c9a..783fd2cec1 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -190,8 +190,6 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, free_result)(MYSQLND_RES_UNBUFFERED * result->row_packet = NULL; } - mysqlnd_mempool_restore_state(result->result_set_memory_pool); - DBG_VOID_RETURN; } /* }}} */ @@ -261,8 +259,6 @@ MYSQLND_METHOD(mysqlnd_result_buffered, free_result)(MYSQLND_RES_BUFFERED * cons set->row_buffers = NULL; } - mysqlnd_mempool_restore_state(set->result_set_memory_pool); - DBG_VOID_RETURN; } /* }}} */ @@ -275,6 +271,12 @@ MYSQLND_METHOD(mysqlnd_res, free_result_buffers)(MYSQLND_RES * result) DBG_ENTER("mysqlnd_res::free_result_buffers"); DBG_INF_FMT("%s", result->unbuf? "unbuffered":(result->stored_data? "buffered":"unknown")); + if (result->meta) { + ZEND_ASSERT(zend_arena_contains(result->memory_pool->arena, result->meta)); + result->meta->m->free_metadata(result->meta); + result->meta = NULL; + } + if (result->unbuf) { result->unbuf->m.free_result(result->unbuf, result->conn? result->conn->stats : NULL); result->unbuf = NULL; @@ -283,6 +285,9 @@ MYSQLND_METHOD(mysqlnd_res, free_result_buffers)(MYSQLND_RES * result) result->stored_data = NULL; } + mysqlnd_mempool_restore_state(result->memory_pool); + mysqlnd_mempool_save_state(result->memory_pool); + DBG_VOID_RETURN; } /* }}} */ @@ -294,12 +299,6 @@ void MYSQLND_METHOD(mysqlnd_res, free_result_contents_internal)(MYSQLND_RES * re { DBG_ENTER("mysqlnd_res::free_result_contents_internal"); - if (result->meta) { - ZEND_ASSERT(zend_arena_contains(result->memory_pool->arena, result->meta)); - result->meta->m->free_metadata(result->meta); - result->meta = NULL; - } - result->m.free_result_buffers(result); DBG_VOID_RETURN; @@ -1926,6 +1925,8 @@ mysqlnd_result_init(const unsigned int field_count) ret->field_count = field_count; ret->m = *mysqlnd_result_get_methods(); + mysqlnd_mempool_save_state(pool); + DBG_RETURN(ret); } /* }}} */ @@ -1941,7 +1942,6 @@ mysqlnd_result_unbuffered_init(MYSQLND_RES *result, const unsigned int field_cou DBG_ENTER("mysqlnd_result_unbuffered_init"); - mysqlnd_mempool_save_state(pool); ret = pool->get_chunk(pool, alloc_size); memset(ret, 0, alloc_size); @@ -1976,12 +1976,10 @@ mysqlnd_result_buffered_zval_init(MYSQLND_RES * result, const unsigned int field DBG_ENTER("mysqlnd_result_buffered_zval_init"); - mysqlnd_mempool_save_state(pool); ret = pool->get_chunk(pool, alloc_size); memset(ret, 0, alloc_size); if (FAIL == mysqlnd_error_info_init(&ret->error_info, 0)) { - mysqlnd_mempool_restore_state(pool); DBG_RETURN(NULL); } @@ -2019,12 +2017,10 @@ mysqlnd_result_buffered_c_init(MYSQLND_RES * result, const unsigned int field_co DBG_ENTER("mysqlnd_result_buffered_c_init"); - mysqlnd_mempool_save_state(pool); ret = pool->get_chunk(pool, alloc_size); memset(ret, 0, alloc_size); if (FAIL == mysqlnd_error_info_init(&ret->error_info, 0)) { - mysqlnd_mempool_restore_state(pool); DBG_RETURN(NULL); }