Skip to content

Commit 2adf1c4

Browse files
committed
Fix #79332: php_istreams are never freed
Releasing the `com_dotnet_istream_wrapper` in `istream_destructor()` is pointless, since `istream_destructor()` is only called when the resource is going to be released. This recursion is not a real issue, though, since the resource is never exposed to userland, and has at most refcount 1, so due to well defined unsigned integer underflow, it never is released twice. However, returning early in this case causes a memory leak which needs to be fixed.
1 parent 6c48da9 commit 2adf1c4

File tree

3 files changed

+20
-10
lines changed

3 files changed

+20
-10
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ PHP NEWS
1414
. Fixed bug #79248 (Traversing empty VT_ARRAY throws com_exception). (cmb)
1515
. Fixed bug #79299 (com_print_typeinfo prints duplicate variables). (Litiano
1616
Moura)
17+
. Fixed bug #79332 (php_istreams are never freed). (cmb)
1718

1819
- DOM:
1920
. Fixed bug #77569: (Write Access Violation in DomImplementation). (Nikita,

ext/com_dotnet/com_persist.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,6 @@ static struct IStreamVtbl php_istream_vtbl = {
248248

249249
static void istream_destructor(php_istream *stm)
250250
{
251-
if (stm->res) {
252-
zend_resource *res = stm->res;
253-
stm->res = NULL;
254-
zend_list_delete(res);
255-
return;
256-
}
257-
258251
if (stm->refcount > 0) {
259252
CoDisconnectObject((IUnknown*)stm, 0);
260253
}
@@ -268,7 +261,6 @@ static void istream_destructor(php_istream *stm)
268261
PHP_COM_DOTNET_API IStream *php_com_wrapper_export_stream(php_stream *stream)
269262
{
270263
php_istream *stm = (php_istream*)CoTaskMemAlloc(sizeof(*stm));
271-
zval *tmp;
272264

273265
if (stm == NULL)
274266
return NULL;
@@ -280,8 +272,7 @@ PHP_COM_DOTNET_API IStream *php_com_wrapper_export_stream(php_stream *stream)
280272
stm->stream = stream;
281273

282274
GC_ADDREF(stream->res);
283-
tmp = zend_list_insert(stm, le_istream);
284-
stm->res = Z_RES_P(tmp);
275+
stm->res = zend_register_resource(stm, le_istream);
285276

286277
return (IStream*)stm;
287278
}

ext/com_dotnet/tests/bug79332.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Bug #79332 (php_istreams are never freed)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('com_dotnet')) die('com_dotnet extension not available');
6+
?>
7+
--FILE--
8+
<?php
9+
$ph = new COMPersistHelper(null);
10+
try {
11+
$ph->LoadFromStream(fopen(__FILE__, 'r'));
12+
} catch (com_exception $ex) {
13+
// use hard-coded message to avoid localization issues
14+
echo "A com_exception has been thrown\n";
15+
}
16+
?>
17+
--EXPECT--
18+
A com_exception has been thrown

0 commit comments

Comments
 (0)