mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
Fix stream_wrapper_unregister() resource leak
Closes GH-8548 Closes GH-8587
This commit is contained in:
parent
82ab848daf
commit
a5a89cc222
3 changed files with 53 additions and 1 deletions
1
NEWS
1
NEWS
|
@ -73,6 +73,7 @@ PHP NEWS
|
||||||
- Streams:
|
- Streams:
|
||||||
. Set IP_BIND_ADDRESS_NO_PORT if available when connecting to remote host.
|
. Set IP_BIND_ADDRESS_NO_PORT if available when connecting to remote host.
|
||||||
(Cristian Rodríguez)
|
(Cristian Rodríguez)
|
||||||
|
. Fixed bug GH-8548 (stream_wrapper_unregister() leaks memory). (ilutov)
|
||||||
|
|
||||||
- Zip:
|
- Zip:
|
||||||
. add ZipArchive::clearError() method
|
. add ZipArchive::clearError() method
|
||||||
|
|
40
Zend/tests/gh8548.phpt
Normal file
40
Zend/tests/gh8548.phpt
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
--TEST--
|
||||||
|
GH-8548: stream_wrapper_unregister() leaks memory
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Wrapper
|
||||||
|
{
|
||||||
|
public $context;
|
||||||
|
|
||||||
|
public function stream_open(string $path, string $mode, int $options): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
if (!stream_wrapper_register('foo', \Wrapper::class)) {
|
||||||
|
throw new \Exception('Could not register stream wrapper');
|
||||||
|
}
|
||||||
|
if (!stream_wrapper_unregister('foo')) {
|
||||||
|
throw new \Exception('Could not unregister stream wrapper');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first iterations will allocate space for things like the resource list
|
||||||
|
for ($i = 0; $i < 5; $i++) {
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
|
||||||
|
$before = memory_get_usage();
|
||||||
|
for ($i = 0; $i < 1000; $i++) {
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
$after = memory_get_usage();
|
||||||
|
|
||||||
|
var_dump($before === $after);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
|
@ -35,9 +35,10 @@
|
||||||
static int le_protocols;
|
static int le_protocols;
|
||||||
|
|
||||||
struct php_user_stream_wrapper {
|
struct php_user_stream_wrapper {
|
||||||
|
php_stream_wrapper wrapper;
|
||||||
char * protoname;
|
char * protoname;
|
||||||
zend_class_entry *ce;
|
zend_class_entry *ce;
|
||||||
php_stream_wrapper wrapper;
|
zend_resource *resource;
|
||||||
};
|
};
|
||||||
|
|
||||||
static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC);
|
static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC);
|
||||||
|
@ -481,10 +482,12 @@ PHP_FUNCTION(stream_wrapper_register)
|
||||||
uwrap->wrapper.wops = &user_stream_wops;
|
uwrap->wrapper.wops = &user_stream_wops;
|
||||||
uwrap->wrapper.abstract = uwrap;
|
uwrap->wrapper.abstract = uwrap;
|
||||||
uwrap->wrapper.is_url = ((flags & PHP_STREAM_IS_URL) != 0);
|
uwrap->wrapper.is_url = ((flags & PHP_STREAM_IS_URL) != 0);
|
||||||
|
uwrap->resource = NULL;
|
||||||
|
|
||||||
rsrc = zend_register_resource(uwrap, le_protocols);
|
rsrc = zend_register_resource(uwrap, le_protocols);
|
||||||
|
|
||||||
if (php_register_url_stream_wrapper_volatile(protocol, &uwrap->wrapper) == SUCCESS) {
|
if (php_register_url_stream_wrapper_volatile(protocol, &uwrap->wrapper) == SUCCESS) {
|
||||||
|
uwrap->resource = rsrc;
|
||||||
RETURN_TRUE;
|
RETURN_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,12 +513,20 @@ PHP_FUNCTION(stream_wrapper_unregister)
|
||||||
RETURN_THROWS();
|
RETURN_THROWS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
php_stream_wrapper *wrapper = zend_hash_find_ptr(php_stream_get_url_stream_wrappers_hash(), protocol);
|
||||||
if (php_unregister_url_stream_wrapper_volatile(protocol) == FAILURE) {
|
if (php_unregister_url_stream_wrapper_volatile(protocol) == FAILURE) {
|
||||||
/* We failed */
|
/* We failed */
|
||||||
php_error_docref(NULL, E_WARNING, "Unable to unregister protocol %s://", ZSTR_VAL(protocol));
|
php_error_docref(NULL, E_WARNING, "Unable to unregister protocol %s://", ZSTR_VAL(protocol));
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZEND_ASSERT(wrapper != NULL);
|
||||||
|
if (wrapper->wops == &user_stream_wops) {
|
||||||
|
struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper *)wrapper;
|
||||||
|
// uwrap will be released by resource destructor
|
||||||
|
zend_list_delete(uwrap->resource);
|
||||||
|
}
|
||||||
|
|
||||||
RETURN_TRUE;
|
RETURN_TRUE;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue