-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix stream_wrapper_unregister() resource leak #8587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the PR!
Indeed, we cannot do this for any of the stable branches, and given that we want to migrate to objects hopefully with PHP 9.0, I have doubts that this change is worth to be done; after all, there are many external extensions which have custom stream wrappers, and all these would need to be updated (possibly in non-trivial ways for BC reasons) for PHP 8.2, and then again for PHP 9.0.
I am not sure, though, whether the API break is necessary at all. Instead of introducing the php_stream_wrapper.type
member, can't we just check whether .wops == &user_stream_wops
? If that is given, we could cast (which requires the restructuring of the internal struct _php_user_stream_wrapper
, but that "only" constitutes an ABI break, so extensions would not be affected at all).
@cmb69 Oh, indeed! I'll make the necessary changes. Do you think the |
a7f2604
to
e0b2ce5
Compare
The |
@cmb69 Thanks. I will investigate if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, 5 iterations were needed before memory stopped increasing. Why that particular number, I'm not sure.
It might even make sense to increase this number, just to be sure that the test works in all circumstances.
Anyhow, the PR looks good to me now. The only issue would be get_resources()
, but that is already documented as debuging tool, with respective caveats.
Can you clarify? Do you mean |
The general problem with |
Ah, of course. We can also delay the freeing until any reference to it goes away, that should work fine. I added the assert because I didn't think there was a way the refcount could increase. |
In my opinion, there shouldn't be a way. :) |
If you're ok with this I would still like to change it, as this could lead to memory corruption otherwise (even if |
Yeah, sure, feel free to improve. :) |
// uwrap will be released by resource destructor | ||
rc_dtor_func((zend_refcounted *)resource); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you use something more standard like zend_list_delete here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I didn't realize EG(regular_list)
had a destructor attached to it that will free the resource. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
phpitnernalsbook.com has a good chapter about resources.
Streams hold a reference to the stream wrapper. User stream wrappers must not be released until the streams themselves are closed.
Streams hold a reference to the stream wrapper. User stream wrappers must not be released until the streams themselves are closed.
Streams hold a reference to the stream wrapper. User stream wrappers must not be released until the streams themselves are closed.
Streams hold a reference to the stream wrapper. User stream wrappers must not be released until the streams themselves are closed.
Closes GH-8548
The changes are bigger than I would've liked to. Let me know if you'd like me to change anything, I'm open to suggestions. The approach of this PR:
php_user_stream_wrapper.wrapper
the first member so that we can cast betweenphp_user_stream_wrapper
andphp_stream_wrapper
php_stream_wrapper
(INTERNAL
orUSER
) so that we know which is whichphp_user_stream_wrapper
so that we can deallocate it when the user stream wrapper is removedTo actually make this testable, I had to introduce a
AUTO_CLOSE_RESOURCE_LIST
env variable that circumvents automatically closing all open resources at the end of the request, as that hides resource leaks. This way the leak is reported both with zmm and asan.This PR is not ABI compatible, so it's targeting master.