diff --git a/NEWS b/NEWS index 7abff44fbb10..6fe3607e3f73 100644 --- a/NEWS +++ b/NEWS @@ -40,6 +40,8 @@ PHP NEWS when getpwnam_r() needs a larger buffer. (Ilia Alshanetsky) . Fixed password_get_info() and password_needs_rehash() accepting malformed bcrypt costs. (Ilia Alshanetsky) + . Fixed bug GH-24256 (fclose() returns false for stream wrappers without + stream_flush()). (Lazizbek Ergashev) - Zip: . Fixed use-after-free when re-entering ZipArchive during destruction or diff --git a/ext/standard/tests/file/gh24256.phpt b/ext/standard/tests/file/gh24256.phpt new file mode 100644 index 000000000000..c1b217349e0e --- /dev/null +++ b/ext/standard/tests/file/gh24256.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-24256 (fclose() returns false for stream wrappers without stream_flush()) +--FILE-- + +--EXPECT-- +int(4) +bool(true) +int(4) +bool(true) diff --git a/main/streams/userspace.c b/main/streams/userspace.c index b42d7f00e973..d9d4aec1bb7a 100644 --- a/main/streams/userspace.c +++ b/main/streams/userspace.c @@ -741,7 +741,13 @@ static int php_userstreamop_flush(php_stream *stream) zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); zend_string_release_ex(func_name, false); - int ret = call_result == SUCCESS && Z_TYPE(retval) != IS_UNDEF && zend_is_true(&retval) ? 0 : -1; + int ret; + if (call_result == FAILURE) { + /* stream_flush is optional, so a missing one is not an error when closing */ + ret = stream->in_free ? 0 : -1; + } else { + ret = Z_TYPE(retval) != IS_UNDEF && zend_is_true(&retval) ? 0 : -1; + } zval_ptr_dtor(&retval);