diff --git a/ext/dba/dba.c b/ext/dba/dba.c index 7982e4255b07c..0944e6e0b5f16 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -256,14 +256,14 @@ static void dba_close_info(dba_info *info) if (info->flags & DBA_PERSISTENT) { php_stream_pclose(info->fp); } else { - php_stream_close(info->fp); + php_stream_free(info->fp, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR); } } if (info->lock.fp) { if (info->flags & DBA_PERSISTENT) { php_stream_pclose(info->lock.fp); } else { - php_stream_close(info->lock.fp); + php_stream_free(info->lock.fp, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR); } } @@ -518,6 +518,17 @@ static zend_always_inline zend_string *php_dba_zend_string_dup_safe(zend_string } } +/* See mysqlnd_fixup_regular_list */ +static void php_dba_fixup_regular_list(php_stream *stream) +{ + dtor_func_t origin_dtor = EG(regular_list).pDestructor; + EG(regular_list).pDestructor = NULL; + zend_hash_index_del(&EG(regular_list), stream->res->handle); + EG(regular_list).pDestructor = origin_dtor; + efree(stream->res); + stream->res = NULL; +} + /* {{{ php_dba_open */ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) { @@ -831,6 +842,9 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) /* do not log errors for .lck file while in read only mode on .lck file */ lock_file_mode = "rb"; connection->info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|IGNORE_PATH|persistent_flag, &opened_path); + if (connection->info->lock.fp && !persistent_flag) { + php_dba_fixup_regular_list(connection->info->lock.fp); + } if (opened_path) { zend_string_release_ex(opened_path, 0); } @@ -844,6 +858,9 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) zend_string *opened_path = NULL; connection->info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, &opened_path); if (connection->info->lock.fp) { + if (!persistent_flag) { + php_dba_fixup_regular_list(connection->info->lock.fp); + } if (is_db_lock) { if (opened_path) { /* replace the path info with the real path of the opened file */ @@ -880,6 +897,9 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) connection->info->fp = connection->info->lock.fp; /* use the same stream for locking and database access */ } else { connection->info->fp = php_stream_open_wrapper(ZSTR_VAL(connection->info->path), file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, NULL); + if (connection->info->fp && !persistent_flag) { + php_dba_fixup_regular_list(connection->info->fp); + } } if (!connection->info->fp) { /* stream operation already wrote an error message */ diff --git a/ext/dba/tests/gh19706.phpt b/ext/dba/tests/gh19706.phpt new file mode 100644 index 0000000000000..4cf3ef5f54d3c --- /dev/null +++ b/ext/dba/tests/gh19706.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-19706 (dba stream resource mismanagement) +--EXTENSIONS-- +dba +--FILE-- + +--CLEAN-- + +--EXPECT-- +object(Dba\Connection)#1 (0) { +} +object(Dba\Connection)#1 (0) { +}