Commit e9ee4c0b9f5 for php.net
commit e9ee4c0b9f5b6f6028187ab87236f2f5fee6fc65
Merge: 250f138329e d88895b103f
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Fri Jul 24 11:30:37 2026 -0400
Merge branch 'PHP-8.5'
* PHP-8.5:
Don't expose a freed stream resource to user filters
diff --cc NEWS
index b2f7d0220a8,ca863b4f381..244ea8ea94f
--- a/NEWS
+++ b/NEWS
@@@ -62,25 -28,18 +62,27 @@@ PH
. Fixed various memory related issues in ext/sockets. (David Carlier)
- Streams:
+ . Added a new IO copy API used by php_stream_copy_to_stream_ex() that
+ leverages platform primitives (sendfile, splice, copy_file_range,
+ TransmitFile) for faster stream copying. (Jakub Zelenka, David Carlier)
+ . Fixed bug GH-22841 (php_stream_copy_to_stream_ex() drops progress
+ notifications when using the copy fast path). (David Carlier)
+ . Fixed bug GH-15836 (Use-after-free when a user stream filter accesses
+ $this->stream during the close flush). (iliaal)
-30 Jul 2026, PHP 8.5.9
+16 Jul 2026, PHP 8.6.0alpha2
- Core:
- . Fixed bug GH-22290 (AST pretty printing does not correctly handle strings
- containing NUL). (iliaal)
- . Fixed bug GH-22206 (missing return in global register detection).
- (P3p111n0)
+ . Sync Boost.Context assembly with 1.91.0. (kn1g78)
+ . Fixed bug GH-22387 (AST pretty-printing drops meaningful parentheses around
+ RHS of instanceof). (timwolla)
+ . Fixed bug GH-15672 and GH-15911 (Stack overflow when an internal function
+ recurses through zend_call_function, such as a self-attached SPL
+ iterator). (iliaal)
. Lock unmodified readonly properties for modification after clone-with.
(NickSdot)
+ . abort() instead of exit() on hard OOM. (realFlowControl)
+ . perf: ZTS: move AG and SCNG into native __thread storage. (henderkes)
- Calendar:
. Fixed bug GH-22602 (gregoriantojd() and juliantojd() integer overflow with
diff --cc ext/standard/user_filters.c
index 986bbbd5f4d,0c27130ee02..126b434713a
--- a/ext/standard/user_filters.c
+++ b/ext/standard/user_filters.c
@@@ -132,36 -123,6 +132,40 @@@ static void userfilter_dtor(php_stream_
zval_ptr_dtor(obj);
}
+static zend_result userfilter_assign_stream(php_stream *stream, zval *obj,
+ zend_string **stream_name_p, uint32_t orig_no_fclose)
+{
+ /* Give the userfilter class a hook back to the stream */
+ const zend_class_entry *old_scope = EG(fake_scope);
+ EG(fake_scope) = Z_OBJCE_P(obj);
+
+ zend_string *stream_name = ZSTR_INIT_LITERAL("stream", false);
+ bool stream_property_exists = Z_OBJ_HT_P(obj)->has_property(Z_OBJ_P(obj), stream_name, ZEND_PROPERTY_EXISTS, NULL);
+ if (stream_property_exists) {
+ zval stream_zval;
- php_stream_to_zval(stream, &stream_zval);
++ if (EXPECTED(stream->res && stream->res->type >= 0)) {
++ php_stream_to_zval(stream, &stream_zval);
++ } else {
++ ZVAL_NULL(&stream_zval);
++ }
+ zend_update_property_ex(Z_OBJCE_P(obj), Z_OBJ_P(obj), stream_name, &stream_zval);
+ /* If property update threw an exception, skip filter execution */
+ if (EG(exception)) {
+ EG(fake_scope) = old_scope;
+ zend_string_release(stream_name);
+ stream->flags &= ~PHP_STREAM_FLAG_NO_FCLOSE;
+ stream->flags |= orig_no_fclose;
+ return FAILURE;
+ }
+ *stream_name_p = stream_name;
+ } else {
+ zend_string_release(stream_name);
+ }
+ EG(fake_scope) = old_scope;
+
+ return SUCCESS;
+}
+
static php_stream_filter_status_t userfilter_filter(
php_stream *stream,
php_stream_filter *thisfilter,