[php-src] master: streams: refactor _php_userstream_data struct to hold zend_object* instead of zval (#24027)

From: Date: Wed, 30 Sep 2026 19:05:00 +0000
Subject: [php-src] master: streams: refactor _php_userstream_data struct to hold zend_object* instead of zval (#24027)
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-141819@lists.php.net to get a copy of this message
Author: Gina Peter Banyard (Girgias) Committer: GitHub (web-flow) Pusher: Girgias Date: 2026-09-30T20:04:57+01:00 Commit: https://github.com/php/php-src/commit/0cd95ddacebc802fc96883e414132eec1e5bb53f Raw diff: https://github.com/php/php-src/commit/0cd95ddacebc802fc96883e414132eec1e5bb53f.diff streams: refactor _php_userstream_data struct to hold zend_object* instead of zval (#24027) This reduces the struct size from 24 to 16 bytes. Using a zend_object* directly also ensures no other zval type could possibly be used. Changed paths: M main/streams/userspace.c Diff: diff --git a/main/streams/userspace.c b/main/streams/userspace.c index 9b6f283c075d..b6177ade8b44 100644 --- a/main/streams/userspace.c +++ b/main/streams/userspace.c @@ -86,7 +86,7 @@ PHP_MINIT_FUNCTION(user_streams) struct _php_userstream_data { struct php_user_stream_wrapper * wrapper; - zval object; + zend_object *object; }; typedef struct _php_userstream_data php_userstream_data_t; @@ -247,33 +247,34 @@ typedef struct _php_userstream_data php_userstream_data_t; }}} **/ -static void user_stream_create_object(struct php_user_stream_wrapper *uwrap, php_stream_context *context, zval *object) +static zend_object* user_stream_create_object(struct php_user_stream_wrapper *uwrap, php_stream_context *context) { ZEND_ASSERT((uwrap->ce->ce_flags & ZEND_ACC_UNINSTANTIABLE) == 0); + zval object; /* create an instance of our class */ - if (object_init_ex(object, uwrap->ce) == FAILURE) { - ZVAL_UNDEF(object); - return; + if (object_init_ex(&object, uwrap->ce) == FAILURE) { + return NULL; } if (context) { GC_ADDREF(context->res); - add_property_resource(object, "context", context->res); + add_property_resource(&object, "context", context->res); } else { - add_property_null(object, "context"); + add_property_null(&object, "context"); } if (EG(exception) != NULL) { - zval_ptr_dtor(object); - ZVAL_UNDEF(object); - return; + zval_ptr_dtor(&object); + return NULL; } if (uwrap->ce->constructor) { zend_call_known_instance_method_with_0_params( - uwrap->ce->constructor, Z_OBJ_P(object), NULL); + uwrap->ce->constructor, Z_OBJ(object), NULL); } + + return Z_OBJ(object); } static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char *filename, const char *mode, @@ -310,8 +311,8 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * /* zend_call_method_if_exists() may unregister the stream wrapper. Hold on to it. */ GC_ADDREF(us->wrapper->resource); - user_stream_create_object(uwrap, context, &us->object); - if (Z_ISUNDEF(us->object)) { + us->object = user_stream_create_object(uwrap, context); + if (!us->object) { goto end; } @@ -322,7 +323,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * ZVAL_NEW_REF(&args[3], &EG(uninitialized_zval)); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_OPEN, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &zretval, 4, args); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &zretval, 4, args); zend_string_release_ex(func_name, false); /* Keep arg3 alive if it has assigned the reference */ @@ -351,7 +352,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * // TODO Warn when assigning a non string value to the reference? /* set wrapper data to be a reference to our object */ - ZVAL_COPY(&stream->wrapperdata, &us->object); + ZVAL_OBJ_COPY(&stream->wrapperdata, us->object); } else { php_stream_wrapper_log_warn(wrapper, context, options, UserspaceCallFailed, @@ -365,7 +366,9 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * FG(user_stream_current_filename) = NULL; PG(in_user_include) = old_in_user_include; if (stream == NULL) { - zval_ptr_dtor(&us->object); + if (us->object) { + OBJ_RELEASE(us->object); + } zend_list_delete(us->wrapper->resource); efree(us); } @@ -402,8 +405,8 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char /* zend_call_method_if_exists() may unregister the stream wrapper. Hold on to it. */ GC_ADDREF(us->wrapper->resource); - user_stream_create_object(uwrap, context, &us->object); - if (Z_TYPE(us->object) == IS_UNDEF) { + us->object = user_stream_create_object(uwrap, context); + if (!us->object) { goto end; } @@ -412,7 +415,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char ZVAL_LONG(&args[1], options); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_DIR_OPEN, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &zretval, 2, args); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &zretval, 2, args); zend_string_release_ex(func_name, false); zval_ptr_dtor(&args[0]); @@ -432,7 +435,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char stream = php_stream_alloc_rel(&php_stream_userspace_dir_ops, us, 0, mode); /* set wrapper data to be a reference to our object */ - ZVAL_COPY(&stream->wrapperdata, &us->object); + ZVAL_OBJ_COPY(&stream->wrapperdata, us->object); } else { php_stream_wrapper_log_warn(wrapper, context, options, UserspaceCallFailed, @@ -443,7 +446,9 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char end: FG(user_stream_current_filename) = NULL; if (stream == NULL) { - zval_ptr_dtor(&us->object); + if (us->object) { + OBJ_RELEASE(us->object); + } zend_list_delete(us->wrapper->resource); efree(us); } @@ -585,7 +590,7 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_ stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE; zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_WRITE, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 1, args); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 1, args); zend_string_release_ex(func_name, false); zval_ptr_dtor(&args[0]); @@ -636,7 +641,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count ZVAL_LONG(&args[0], count); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_READ, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 1, args); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 1, args); zend_string_release_ex(func_name, false); if (UNEXPECTED(Z_ISUNDEF(retval))) { @@ -678,7 +683,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count /* since the user stream has no way of setting the eof flag directly, we need to ask it if we hit eof */ func_name = ZSTR_INIT_LITERAL(USERSTREAM_EOF, false); - call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); + call_result = zend_call_method_if_exists(us->object, func_name, &retval, 0, NULL); zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { @@ -717,13 +722,13 @@ static int php_userstreamop_close(php_stream *stream, int close_handle) assert(us != NULL); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_CLOSE, false); - zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); + zend_call_method_if_exists(us->object, func_name, &retval, 0, NULL); zend_string_release_ex(func_name, false); zval_ptr_dtor(&retval); - zval_ptr_dtor(&us->object); - ZVAL_UNDEF(&us->object); + ZEND_ASSERT(us->object != NULL); + OBJ_RELEASE(us->object); efree(us); @@ -738,7 +743,7 @@ static int php_userstreamop_flush(php_stream *stream) assert(us != NULL); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_FLUSH, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); + zend_result call_result = zend_call_method_if_exists(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; @@ -764,7 +769,7 @@ static int php_userstreamop_seek(php_stream *stream, zend_off_t offset, int when stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE; zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_SEEK, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 2, args); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 2, args); zend_string_release_ex(func_name, false); if (call_result == FAILURE) { @@ -791,7 +796,7 @@ static int php_userstreamop_seek(php_stream *stream, zend_off_t offset, int when /* now determine where we are */ func_name = ZSTR_INIT_LITERAL(USERSTREAM_TELL, false); - call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); + call_result = zend_call_method_if_exists(us->object, func_name, &retval, 0, NULL); zend_string_release_ex(func_name, false); if (call_result == SUCCESS && Z_TYPE(retval) == IS_LONG) { @@ -859,7 +864,7 @@ static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb) int ret = -1; zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_STAT, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 0, NULL); zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { @@ -887,7 +892,7 @@ static int user_stream_set_check_liveliness(php_stream *stream, const php_userst zval retval; zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_EOF, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 0, NULL); zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { @@ -937,7 +942,7 @@ static int user_stream_set_locking(php_stream *stream, const php_userstream_data /* TODO wouldblock */ zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_LOCK, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 1, &zlock); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 1, &zlock); zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { @@ -972,7 +977,7 @@ static int user_stream_set_truncation(php_stream *stream, const php_userstream_d if (value == PHP_STREAM_TRUNCATE_SUPPORTED) { zval zstr; ZVAL_STR(&zstr, func_name); - bool is_callable = zend_is_callable_ex(&zstr, Z_OBJ(us->object), IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, NULL, NULL); + bool is_callable = zend_is_callable_ex(&zstr, us->object, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, NULL, NULL); // Frees func_name zval_ptr_dtor(&zstr); return is_callable ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; @@ -990,7 +995,7 @@ static int user_stream_set_truncation(php_stream *stream, const php_userstream_d zval size; ZVAL_LONG(&size, (zend_long)new_size); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 1, &size); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 1, &size); zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { @@ -1034,7 +1039,7 @@ static int user_stream_set_option(php_stream *stream, const php_userstream_data_ zval retval; zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_SET_OPTION, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 3, args); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 3, args); zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { @@ -1088,12 +1093,11 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract; zval zretval; zval args[1]; - zval object; int ret = 0; /* create an instance of our class */ - user_stream_create_object(uwrap, context, &object); - if (Z_TYPE(object) == IS_UNDEF) { + zend_object *object = user_stream_create_object(uwrap, context); + if (object == NULL) { return ret; } @@ -1102,10 +1106,10 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_UNLINK, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(object), func_name, &zretval, 1, args); + zend_result call_result = zend_call_method_if_exists(object, func_name, &zretval, 1, args); zend_string_release_ex(func_name, false); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&object); + OBJ_RELEASE(object); if (UNEXPECTED(call_result == FAILURE)) { php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, @@ -1126,12 +1130,11 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract; zval zretval; zval args[2]; - zval object; int ret = 0; /* create an instance of our class */ - user_stream_create_object(uwrap, context, &object); - if (Z_TYPE(object) == IS_UNDEF) { + zend_object *object = user_stream_create_object(uwrap, context); + if (object == NULL) { return ret; } @@ -1140,11 +1143,11 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from ZVAL_STRING(&args[1], url_to); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_RENAME, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(object), func_name, &zretval, 2, args); + zend_result call_result = zend_call_method_if_exists(object, func_name, &zretval, 2, args); zend_string_release_ex(func_name, false); zval_ptr_dtor(&args[1]); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&object); + OBJ_RELEASE(object); if (UNEXPECTED(call_result == FAILURE)) { php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, @@ -1165,12 +1168,11 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url, int struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract; zval zretval; zval args[3]; - zval object; int ret = 0; /* create an instance of our class */ - user_stream_create_object(uwrap, context, &object); - if (Z_TYPE(object) == IS_UNDEF) { + zend_object *object = user_stream_create_object(uwrap, context); + if (object == NULL) { return ret; } @@ -1180,10 +1182,10 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url, int ZVAL_LONG(&args[2], options); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_MKDIR, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(object), func_name, &zretval, 3, args); + zend_result call_result = zend_call_method_if_exists(object, func_name, &zretval, 3, args); zend_string_release_ex(func_name, false); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&object); + OBJ_RELEASE(object); if (UNEXPECTED(call_result == FAILURE)) { php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, @@ -1204,12 +1206,11 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract; zval zretval; zval args[2]; - zval object; int ret = 0; /* create an instance of our class */ - user_stream_create_object(uwrap, context, &object); - if (Z_TYPE(object) == IS_UNDEF) { + zend_object *object = user_stream_create_object(uwrap, context); + if (object == NULL) { return ret; } @@ -1218,10 +1219,10 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, ZVAL_LONG(&args[1], options); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_RMDIR, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(object), func_name, &zretval, 2, args); + zend_result call_result = zend_call_method_if_exists(object, func_name, &zretval, 2, args); zend_string_release_ex(func_name, false); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&object); + OBJ_RELEASE(object); if (UNEXPECTED(call_result == FAILURE)) { php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, @@ -1242,7 +1243,6 @@ static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, i struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract; zval zretval; zval args[3]; - zval object; int ret = 0; switch(option) { @@ -1271,8 +1271,8 @@ static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, i } /* create an instance of our class */ - user_stream_create_object(uwrap, context, &object); - if (Z_TYPE(object) == IS_UNDEF) { + zend_object *object = user_stream_create_object(uwrap, context); + if (object == NULL) { zval_ptr_dtor(&args[2]); return ret; } @@ -1282,11 +1282,11 @@ static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, i ZVAL_LONG(&args[1], option); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_METADATA, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(object), func_name, &zretval, 3, args); + zend_result call_result = zend_call_method_if_exists(object, func_name, &zretval, 3, args); zend_string_release_ex(func_name, false); zval_ptr_dtor(&args[2]); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&object); + OBJ_RELEASE(object); if (UNEXPECTED(call_result == FAILURE)) { php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, @@ -1308,12 +1308,11 @@ static int user_wrapper_stat_url(php_stream_wrapper *wrapper, const char *url, i struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract; zval zretval; zval args[2]; - zval object; int ret = -1; /* create an instance of our class */ - user_stream_create_object(uwrap, context, &object); - if (Z_TYPE(object) == IS_UNDEF) { + zend_object *object = user_stream_create_object(uwrap, context); + if (object == NULL) { return -1; } @@ -1322,10 +1321,10 @@ static int user_wrapper_stat_url(php_stream_wrapper *wrapper, const char *url, i ZVAL_LONG(&args[1], flags); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_STATURL, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(object), func_name, &zretval, 2, args); + zend_result call_result = zend_call_method_if_exists(object, func_name, &zretval, 2, args); zend_string_release_ex(func_name, false); zval_ptr_dtor(&args[0]); - zval_ptr_dtor(&object); + OBJ_RELEASE(object); if (UNEXPECTED(call_result == FAILURE)) { php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, NotImplemented, @@ -1360,7 +1359,7 @@ static ssize_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t co } zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_DIR_READ, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 0, NULL); zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) { @@ -1397,12 +1396,12 @@ static int php_userstreamop_closedir(php_stream *stream, int close_handle) assert(us != NULL); zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_DIR_CLOSE, false); - zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); + zend_call_method_if_exists(us->object, func_name, &retval, 0, NULL); zend_string_release_ex(func_name, false); zval_ptr_dtor(&retval); - zval_ptr_dtor(&us->object); - ZVAL_UNDEF(&us->object); + ZEND_ASSERT(us->object != NULL); + OBJ_RELEASE(us->object); efree(us); return 0; @@ -1414,7 +1413,7 @@ static int php_userstreamop_rewinddir(php_stream *stream, zend_off_t offset, int php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract; zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_DIR_REWIND, false); - zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 0, NULL); + zend_call_method_if_exists(us->object, func_name, &retval, 0, NULL); zend_string_release_ex(func_name, false); zval_ptr_dtor(&retval); @@ -1446,7 +1445,7 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE; zend_string *func_name = ZSTR_INIT_LITERAL(USERSTREAM_CAST, false); - zend_result call_result = zend_call_method_if_exists(Z_OBJ(us->object), func_name, &retval, 1, args); + zend_result call_result = zend_call_method_if_exists(us->object, func_name, &retval, 1, args); zend_string_release_ex(func_name, false); if (UNEXPECTED(call_result == FAILURE)) {

« previous php.cvs (#141819) next »