From 73e070a614f90c87a15799693f2bddc3d5842545 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Mon, 20 Jul 2020 13:47:35 +0100 Subject: [PATCH] Refactor user streams to use ZPP class check Closes GH-5876 --- ext/standard/tests/file/userstreams.phpt | 6 +- main/streams/userspace.c | 81 +++++++++++------------- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/ext/standard/tests/file/userstreams.phpt b/ext/standard/tests/file/userstreams.phpt index 5b753e02e4f..101604f5abc 100644 --- a/ext/standard/tests/file/userstreams.phpt +++ b/ext/standard/tests/file/userstreams.phpt @@ -156,8 +156,11 @@ class mystream } -if (@stream_wrapper_register("bogus", "class_not_exist")) { +try { + stream_wrapper_register("bogus", "class_not_exist"); die("Registered a non-existent class!!!???"); +} catch (\TypeError $e) { + echo $e->getMessage() . \PHP_EOL; } echo "Not Registered\n"; @@ -315,6 +318,7 @@ echo $data . "\n"; ?> --EXPECT-- +stream_wrapper_register(): Argument #2 ($classname) must be a valid class name, class_not_exist given Not Registered Registered Registered diff --git a/main/streams/userspace.c b/main/streams/userspace.c index d9fc112aa1e..f6381a0014c 100644 --- a/main/streams/userspace.c +++ b/main/streams/userspace.c @@ -36,7 +36,6 @@ static int le_protocols; struct php_user_stream_wrapper { char * protoname; - char * classname; zend_class_entry *ce; php_stream_wrapper wrapper; }; @@ -71,7 +70,6 @@ static void stream_wrapper_dtor(zend_resource *rsrc) struct php_user_stream_wrapper * uwrap = (struct php_user_stream_wrapper*)rsrc->ptr; efree(uwrap->protoname); - efree(uwrap->classname); efree(uwrap); } @@ -375,7 +373,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char * ZVAL_COPY(&stream->wrapperdata, &us->object); } else { php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_OPEN "\" call failed", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); } /* destroy everything else */ @@ -444,7 +442,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char ZVAL_COPY(&stream->wrapperdata, &us->object); } else { php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_DIR_OPEN "\" call failed", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); } /* destroy everything else */ @@ -468,38 +466,35 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char /* {{{ Registers a custom URL protocol handler class */ PHP_FUNCTION(stream_wrapper_register) { - zend_string *protocol, *classname; - struct php_user_stream_wrapper * uwrap; + zend_string *protocol; + struct php_user_stream_wrapper *uwrap; + zend_class_entry *ce = NULL; zend_resource *rsrc; zend_long flags = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &protocol, &classname, &flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SC|l", &protocol, &ce, &flags) == FAILURE) { RETURN_THROWS(); } uwrap = (struct php_user_stream_wrapper *)ecalloc(1, sizeof(*uwrap)); + uwrap->ce = ce; uwrap->protoname = estrndup(ZSTR_VAL(protocol), ZSTR_LEN(protocol)); - uwrap->classname = estrndup(ZSTR_VAL(classname), ZSTR_LEN(classname)); uwrap->wrapper.wops = &user_stream_wops; uwrap->wrapper.abstract = uwrap; uwrap->wrapper.is_url = ((flags & PHP_STREAM_IS_URL) != 0); rsrc = zend_register_resource(uwrap, le_protocols); - if ((uwrap->ce = zend_lookup_class(classname)) != NULL) { - if (php_register_url_stream_wrapper_volatile(protocol, &uwrap->wrapper) == SUCCESS) { - RETURN_TRUE; - } else { - /* We failed. But why? */ - if (zend_hash_exists(php_stream_get_url_stream_wrappers_hash(), protocol)) { - php_error_docref(NULL, E_WARNING, "Protocol %s:// is already defined.", ZSTR_VAL(protocol)); - } else { - /* Hash doesn't exist so it must have been an invalid protocol scheme */ - php_error_docref(NULL, E_WARNING, "Invalid protocol scheme specified. Unable to register wrapper class %s to %s://", ZSTR_VAL(classname), ZSTR_VAL(protocol)); - } - } + if (php_register_url_stream_wrapper_volatile(protocol, &uwrap->wrapper) == SUCCESS) { + RETURN_TRUE; + } + + /* We failed. But why? */ + if (zend_hash_exists(php_stream_get_url_stream_wrappers_hash(), protocol)) { + php_error_docref(NULL, E_WARNING, "Protocol %s:// is already defined.", ZSTR_VAL(protocol)); } else { - php_error_docref(NULL, E_WARNING, "Class '%s' is undefined", ZSTR_VAL(classname)); + /* Hash doesn't exist so it must have been an invalid protocol scheme */ + php_error_docref(NULL, E_WARNING, "Invalid protocol scheme specified. Unable to register wrapper class %s to %s://", ZSTR_VAL(uwrap->ce->name), ZSTR_VAL(protocol)); } zend_list_delete(rsrc); @@ -596,14 +591,14 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_ } } else { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_WRITE " is not implemented!", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); didwrite = -1; } /* don't allow strange buffer overruns due to bogus return */ if (didwrite > 0 && didwrite > count) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_WRITE " wrote " ZEND_LONG_FMT " bytes more data than requested (" ZEND_LONG_FMT " written, " ZEND_LONG_FMT " max)", - us->wrapper->classname, + ZSTR_VAL(us->wrapper->ce->name), (zend_long)(didwrite - count), (zend_long)didwrite, (zend_long)count); didwrite = count; } @@ -643,7 +638,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count if (call_result == FAILURE) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_READ " is not implemented!", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); return -1; } @@ -659,7 +654,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count if (didread > 0) { if (didread > count) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_READ " - read " ZEND_LONG_FMT " bytes more data than requested (" ZEND_LONG_FMT " read, " ZEND_LONG_FMT " max) - excess data will be lost", - us->wrapper->classname, (zend_long)(didread - count), (zend_long)didread, (zend_long)count); + ZSTR_VAL(us->wrapper->ce->name), (zend_long)(didread - count), (zend_long)didread, (zend_long)count); didread = count; } memcpy(buf, Z_STRVAL(retval), didread); @@ -688,7 +683,7 @@ static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count } else if (call_result == FAILURE) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); stream->eof = 1; } @@ -812,7 +807,7 @@ static int php_userstreamop_seek(php_stream *stream, zend_off_t offset, int when *newoffs = Z_LVAL(retval); ret = 0; } else if (call_result == FAILURE) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_TELL " is not implemented!", us->wrapper->classname); + php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_TELL " is not implemented!", ZSTR_VAL(us->wrapper->ce->name)); ret = -1; } else { ret = -1; @@ -884,7 +879,7 @@ static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb) } else { if (call_result == FAILURE) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_STAT " is not implemented!", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); } } @@ -913,7 +908,7 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value ret = PHP_STREAM_OPTION_RETURN_ERR; php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); } zval_ptr_dtor(&retval); zval_ptr_dtor(&func_name); @@ -954,7 +949,7 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value ret = PHP_STREAM_OPTION_RETURN_OK; } else { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_LOCK " is not implemented!", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); ret = PHP_STREAM_OPTION_RETURN_ERR; } } @@ -993,12 +988,12 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value } else { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_TRUNCATE " did not return a boolean!", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); } } else { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_TRUNCATE " is not implemented!", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); } zval_ptr_dtor(&retval); zval_ptr_dtor(&args[0]); @@ -1053,7 +1048,7 @@ static int php_userstreamop_set_option(php_stream *stream, int option, int value if (call_result == FAILURE) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_SET_OPTION " is not implemented!", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); ret = PHP_STREAM_OPTION_RETURN_ERR; } else if (zend_is_true(&retval)) { ret = PHP_STREAM_OPTION_RETURN_OK; @@ -1104,7 +1099,7 @@ static int user_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) { ret = (Z_TYPE(zretval) == IS_TRUE); } else if (call_result == FAILURE) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_UNLINK " is not implemented!", uwrap->classname); + php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_UNLINK " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } /* clean up */ @@ -1148,7 +1143,7 @@ static int user_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) { ret = (Z_TYPE(zretval) == IS_TRUE); } else if (call_result == FAILURE) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_RENAME " is not implemented!", uwrap->classname); + php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_RENAME " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } /* clean up */ @@ -1194,7 +1189,7 @@ static int user_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url, int if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) { ret = (Z_TYPE(zretval) == IS_TRUE); } else if (call_result == FAILURE) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_MKDIR " is not implemented!", uwrap->classname); + php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_MKDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } /* clean up */ @@ -1240,7 +1235,7 @@ static int user_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) { ret = (Z_TYPE(zretval) == IS_TRUE); } else if (call_result == FAILURE) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_RMDIR " is not implemented!", uwrap->classname); + php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_RMDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } /* clean up */ @@ -1310,7 +1305,7 @@ static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, i if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) { ret = Z_TYPE(zretval) == IS_TRUE; } else if (call_result == FAILURE) { - php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_METADATA " is not implemented!", uwrap->classname); + php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_METADATA " is not implemented!", ZSTR_VAL(uwrap->ce->name)); } /* clean up */ @@ -1361,7 +1356,7 @@ static int user_wrapper_stat_url(php_stream_wrapper *wrapper, const char *url, i } else { if (call_result == FAILURE) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_STATURL " is not implemented!", - uwrap->classname); + ZSTR_VAL(uwrap->ce->name)); } } @@ -1405,7 +1400,7 @@ static ssize_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t co didread = sizeof(php_stream_dirent); } else if (call_result == FAILURE) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_DIR_READ " is not implemented!", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); } zval_ptr_dtor(&retval); @@ -1491,7 +1486,7 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) do { if (call_result == FAILURE) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_CAST " is not implemented!", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); break; } if (!zend_is_true(&retval)) { @@ -1500,12 +1495,12 @@ static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr) php_stream_from_zval_no_verify(intstream, &retval); if (!intstream) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_CAST " must return a stream resource", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); break; } if (intstream == stream) { php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_CAST " must not return itself", - us->wrapper->classname); + ZSTR_VAL(us->wrapper->ce->name)); intstream = NULL; break; }