mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +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:
|
||||
. Set IP_BIND_ADDRESS_NO_PORT if available when connecting to remote host.
|
||||
(Cristian Rodríguez)
|
||||
. Fixed bug GH-8548 (stream_wrapper_unregister() leaks memory). (ilutov)
|
||||
|
||||
- Zip:
|
||||
. 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;
|
||||
|
||||
struct php_user_stream_wrapper {
|
||||
php_stream_wrapper wrapper;
|
||||
char * protoname;
|
||||
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);
|
||||
|
@ -481,10 +482,12 @@ PHP_FUNCTION(stream_wrapper_register)
|
|||
uwrap->wrapper.wops = &user_stream_wops;
|
||||
uwrap->wrapper.abstract = uwrap;
|
||||
uwrap->wrapper.is_url = ((flags & PHP_STREAM_IS_URL) != 0);
|
||||
uwrap->resource = NULL;
|
||||
|
||||
rsrc = zend_register_resource(uwrap, le_protocols);
|
||||
|
||||
if (php_register_url_stream_wrapper_volatile(protocol, &uwrap->wrapper) == SUCCESS) {
|
||||
uwrap->resource = rsrc;
|
||||
RETURN_TRUE;
|
||||
}
|
||||
|
||||
|
@ -510,12 +513,20 @@ PHP_FUNCTION(stream_wrapper_unregister)
|
|||
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) {
|
||||
/* We failed */
|
||||
php_error_docref(NULL, E_WARNING, "Unable to unregister protocol %s://", ZSTR_VAL(protocol));
|
||||
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;
|
||||
}
|
||||
/* }}} */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue